Subversion Repositories HelenOS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 jermar 1
/*
319 jermar 2
 * Copyright (C) 2003-2004 Jakub Jermar
1 jermar 3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 *
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
13
 *   documentation and/or other materials provided with the distribution.
14
 * - The name of the author may not be used to endorse or promote products
15
 *   derived from this software without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
28
 
29
#include <arch/mm/tlb.h>
130 decky 30
#include <arch/mm/asid.h>
1 jermar 31
#include <mm/tlb.h>
391 jermar 32
#include <mm/page.h>
33
#include <mm/vm.h>
1 jermar 34
#include <arch/cp0.h>
35
#include <panic.h>
36
#include <arch.h>
268 palkovsky 37
#include <symtab.h>
391 jermar 38
#include <synch/spinlock.h>
39
#include <print.h>
396 jermar 40
#include <debug.h>
268 palkovsky 41
 
391 jermar 42
static void tlb_refill_fail(struct exception_regdump *pstate);
43
static void tlb_invalid_fail(struct exception_regdump *pstate);
44
static void tlb_modified_fail(struct exception_regdump *pstate);
45
 
394 jermar 46
static pte_t *find_mapping_and_check(__address badvaddr);
396 jermar 47
static void prepare_entry_lo(entry_lo_t *lo, bool g, bool v, bool d, int c, __address pfn);
394 jermar 48
 
391 jermar 49
/** Initialize TLB
50
 *
51
 * Initialize TLB.
52
 * Invalidate all entries and mark wired entries.
53
 */
389 jermar 54
void tlb_init_arch(void)
55
{
56
	int i;
57
 
58
	cp0_pagemask_write(TLB_PAGE_MASK_16K);
59
	cp0_entry_hi_write(0);
60
	cp0_entry_lo0_write(0);
61
	cp0_entry_lo1_write(0);
62
 
63
	/*
64
	 * Invalidate all entries.
65
	 */
66
	for (i = 0; i < TLB_SIZE; i++) {
391 jermar 67
		cp0_index_write(i);
389 jermar 68
		tlbwi();
69
	}
70
 
71
	/*
72
	 * The kernel is going to make use of some wired
391 jermar 73
	 * entries (e.g. mapping kernel stacks in kseg3).
389 jermar 74
	 */
75
	cp0_wired_write(TLB_WIRED);
76
}
77
 
391 jermar 78
/** Process TLB Refill Exception
79
 *
80
 * Process TLB Refill Exception.
81
 *
82
 * @param pstate Interrupted register context.
83
 */
317 palkovsky 84
void tlb_refill(struct exception_regdump *pstate)
1 jermar 85
{
396 jermar 86
	entry_lo_t lo;
391 jermar 87
	__address badvaddr;
88
	pte_t *pte;
89
 
90
	badvaddr = cp0_badvaddr_read();
91
 
394 jermar 92
	spinlock_lock(&VM->lock);		
93
	pte = find_mapping_and_check(badvaddr);
94
	if (!pte)
391 jermar 95
		goto fail;
96
 
97
	/*
394 jermar 98
	 * Record access to PTE.
391 jermar 99
	 */
394 jermar 100
	pte->a = 1;
391 jermar 101
 
394 jermar 102
	prepare_entry_lo(&lo, pte->g, pte->v, pte->d, pte->c, pte->pfn);
103
 
391 jermar 104
	/*
105
	 * New entry is to be inserted into TLB
106
	 */
107
	if ((badvaddr/PAGE_SIZE) % 2 == 0) {
396 jermar 108
		cp0_entry_lo0_write(lo.value);
391 jermar 109
		cp0_entry_lo1_write(0);
110
	}
111
	else {
112
		cp0_entry_lo0_write(0);
396 jermar 113
		cp0_entry_lo1_write(lo.value);
391 jermar 114
	}
115
	tlbwr();
116
 
117
	spinlock_unlock(&VM->lock);
118
	return;
119
 
120
fail:
121
	spinlock_unlock(&VM->lock);
122
	tlb_refill_fail(pstate);
123
}
124
 
394 jermar 125
/** Process TLB Invalid Exception
126
 *
127
 * Process TLB Invalid Exception.
128
 *
129
 * @param pstate Interrupted register context.
130
 */
391 jermar 131
void tlb_invalid(struct exception_regdump *pstate)
132
{
396 jermar 133
	tlb_index_t index;
394 jermar 134
	__address badvaddr;
396 jermar 135
	entry_lo_t lo;
394 jermar 136
	pte_t *pte;
137
 
138
	badvaddr = cp0_badvaddr_read();
139
 
140
	/*
141
	 * Locate the faulting entry in TLB.
142
	 */
143
	tlbp();
396 jermar 144
	index.value = cp0_index_read();
394 jermar 145
 
146
	spinlock_lock(&VM->lock);	
147
 
148
	/*
149
	 * Fail if the entry is not in TLB.
150
	 */
396 jermar 151
	if (index.p) {
152
		printf("TLB entry not found.\n");
394 jermar 153
		goto fail;
396 jermar 154
	}
394 jermar 155
 
156
	pte = find_mapping_and_check(badvaddr);
157
	if (!pte)
158
		goto fail;
159
 
160
	/*
161
	 * Read the faulting TLB entry.
162
	 */
163
	tlbr();
164
 
165
	/*
166
	 * Record access to PTE.
167
	 */
168
	pte->a = 1;
169
 
170
	prepare_entry_lo(&lo, pte->g, pte->v, pte->d, pte->c, pte->pfn);
171
 
172
	/*
173
	 * The entry is to be updated in TLB.
174
	 */
175
	if ((badvaddr/PAGE_SIZE) % 2 == 0)
396 jermar 176
		cp0_entry_lo0_write(lo.value);
394 jermar 177
	else
396 jermar 178
		cp0_entry_lo1_write(lo.value);
394 jermar 179
	tlbwi();
180
 
181
	spinlock_unlock(&VM->lock);	
182
	return;
183
 
184
fail:
185
	spinlock_unlock(&VM->lock);
391 jermar 186
	tlb_invalid_fail(pstate);
187
}
188
 
394 jermar 189
/** Process TLB Modified Exception
190
 *
191
 * Process TLB Modified Exception.
192
 *
193
 * @param pstate Interrupted register context.
194
 */
391 jermar 195
void tlb_modified(struct exception_regdump *pstate)
196
{
396 jermar 197
	tlb_index_t index;
394 jermar 198
	__address badvaddr;
396 jermar 199
	entry_lo_t lo;
394 jermar 200
	pte_t *pte;
201
 
202
	badvaddr = cp0_badvaddr_read();
203
 
204
	/*
205
	 * Locate the faulting entry in TLB.
206
	 */
207
	tlbp();
396 jermar 208
	index.value = cp0_index_read();
394 jermar 209
 
210
	spinlock_lock(&VM->lock);	
211
 
212
	/*
213
	 * Fail if the entry is not in TLB.
214
	 */
396 jermar 215
	if (index.p) {
216
		printf("TLB entry not found.\n");
394 jermar 217
		goto fail;
396 jermar 218
	}
394 jermar 219
 
220
	pte = find_mapping_and_check(badvaddr);
221
	if (!pte)
222
		goto fail;
223
 
224
	/*
225
	 * Fail if the page is not writable.
226
	 */
227
	if (!pte->w)
228
		goto fail;
229
 
230
	/*
231
	 * Read the faulting TLB entry.
232
	 */
233
	tlbr();
234
 
235
	/*
236
	 * Record access and write to PTE.
237
	 */
238
	pte->a = 1;
239
	pte->d = 1;
240
 
241
	prepare_entry_lo(&lo, pte->g, pte->v, pte->w, pte->c, pte->pfn);
242
 
243
	/*
244
	 * The entry is to be updated in TLB.
245
	 */
246
	if ((badvaddr/PAGE_SIZE) % 2 == 0)
396 jermar 247
		cp0_entry_lo0_write(lo.value);
394 jermar 248
	else
396 jermar 249
		cp0_entry_lo1_write(lo.value);
394 jermar 250
	tlbwi();
251
 
252
	spinlock_unlock(&VM->lock);	
253
	return;
254
 
255
fail:
256
	spinlock_unlock(&VM->lock);
391 jermar 257
	tlb_modified_fail(pstate);
258
}
259
 
260
void tlb_refill_fail(struct exception_regdump *pstate)
261
{
324 palkovsky 262
	char *symbol = "";
263
	char *sym2 = "";
264
 
332 palkovsky 265
	char *s = get_symtab_entry(pstate->epc);
266
	if (s)
267
		symbol = s;
268
	s = get_symtab_entry(pstate->ra);
269
	if (s)
270
		sym2 = s;
391 jermar 271
	panic("%X: TLB Refill Exception at %X(%s<-%s)\n", cp0_badvaddr_read(), pstate->epc, symbol, sym2);
1 jermar 272
}
273
 
391 jermar 274
 
275
void tlb_invalid_fail(struct exception_regdump *pstate)
1 jermar 276
{
268 palkovsky 277
	char *symbol = "";
278
 
332 palkovsky 279
	char *s = get_symtab_entry(pstate->epc);
280
	if (s)
281
		symbol = s;
394 jermar 282
	panic("%X: TLB Invalid Exception at %X(%s)\n", cp0_badvaddr_read(), pstate->epc, symbol);
1 jermar 283
}
284
 
391 jermar 285
void tlb_modified_fail(struct exception_regdump *pstate)
389 jermar 286
{
287
	char *symbol = "";
288
 
289
	char *s = get_symtab_entry(pstate->epc);
290
	if (s)
291
		symbol = s;
394 jermar 292
	panic("%X: TLB Modified Exception at %X(%s)\n", cp0_badvaddr_read(), pstate->epc, symbol);
389 jermar 293
}
294
 
396 jermar 295
/** Invalidate TLB entries with specified ASID
296
 *
297
 * Invalidate TLB entries with specified ASID.
298
 *
299
 * @param asid ASID.
300
 */
301
void tlb_invalidate(asid_t asid)
1 jermar 302
{
396 jermar 303
	entry_hi_t hi;
130 decky 304
	pri_t pri;
396 jermar 305
	int i;	
130 decky 306
 
396 jermar 307
	ASSERT(asid != ASID_INVALID);
308
 
130 decky 309
	pri = cpu_priority_high();
310
 
396 jermar 311
	for (i = 0; i < TLB_SIZE; i++) {
312
		cp0_index_write(i);
313
		tlbr();
314
 
315
		hi.value = cp0_entry_hi_read();
316
		if (hi.asid == asid) {
317
			cp0_pagemask_write(TLB_PAGE_MASK_16K);
318
			cp0_entry_hi_write(0);
319
			cp0_entry_lo0_write(0);
320
			cp0_entry_lo1_write(0);
321
			tlbwi();
322
		}
323
	}
130 decky 324
 
325
	cpu_priority_restore(pri);
1 jermar 326
}
394 jermar 327
 
328
/** Try to find PTE for faulting address
329
 *
330
 * Try to find PTE for faulting address.
331
 * The VM->lock must be held on entry to this function.
332
 *
333
 * @param badvaddr Faulting virtual address.
334
 *
335
 * @return PTE on success, NULL otherwise.
336
 */
337
pte_t *find_mapping_and_check(__address badvaddr)
338
{
396 jermar 339
	entry_hi_t hi;
394 jermar 340
	pte_t *pte;
341
 
396 jermar 342
	hi.value = cp0_entry_hi_read();
394 jermar 343
 
344
	/*
345
	 * Handler cannot succeed if the ASIDs don't match.
346
	 */
396 jermar 347
	if (hi.asid != VM->asid) {
348
		printf("EntryHi.asid=%d, VM->asid=%d\n", hi.asid, VM->asid);
394 jermar 349
		return NULL;
396 jermar 350
	}
394 jermar 351
 
352
	/*
353
	 * Handler cannot succeed if badvaddr has no mapping.
354
	 */
355
	pte = find_mapping(badvaddr, 0);
396 jermar 356
	if (!pte) {
357
		printf("No such mapping.\n");
394 jermar 358
		return NULL;
396 jermar 359
	}
394 jermar 360
 
361
	/*
362
	 * Handler cannot succeed if the mapping is marked as invalid.
363
	 */
396 jermar 364
	if (!pte->v) {
365
		printf("Invalid mapping.\n");
394 jermar 366
		return NULL;
396 jermar 367
	}
394 jermar 368
 
369
	return pte;
370
}
371
 
396 jermar 372
void prepare_entry_lo(entry_lo_t *lo, bool g, bool v, bool d, int c, __address pfn)
394 jermar 373
{
374
	lo->g = g;
375
	lo->v = v;
376
	lo->d = d;
377
	lo->c = c;
378
	lo->pfn = pfn;
379
	lo->zero = 0;
380
}