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;
397 jermar 89
 
90
// debug	
91
	entry_hi_t hi;
92
 
391 jermar 93
	badvaddr = cp0_badvaddr_read();
397 jermar 94
 
95
// debug
96
	hi.value = cp0_entry_hi_read();
97
	printf("TLB Refill: hi.vnp2=%X\n", hi.vpn2);
391 jermar 98
 
394 jermar 99
	spinlock_lock(&VM->lock);		
100
	pte = find_mapping_and_check(badvaddr);
101
	if (!pte)
391 jermar 102
		goto fail;
103
 
104
	/*
394 jermar 105
	 * Record access to PTE.
391 jermar 106
	 */
394 jermar 107
	pte->a = 1;
391 jermar 108
 
394 jermar 109
	prepare_entry_lo(&lo, pte->g, pte->v, pte->d, pte->c, pte->pfn);
110
 
391 jermar 111
	/*
112
	 * New entry is to be inserted into TLB
113
	 */
114
	if ((badvaddr/PAGE_SIZE) % 2 == 0) {
396 jermar 115
		cp0_entry_lo0_write(lo.value);
391 jermar 116
		cp0_entry_lo1_write(0);
117
	}
118
	else {
119
		cp0_entry_lo0_write(0);
396 jermar 120
		cp0_entry_lo1_write(lo.value);
391 jermar 121
	}
122
	tlbwr();
123
 
124
	spinlock_unlock(&VM->lock);
125
	return;
126
 
127
fail:
128
	spinlock_unlock(&VM->lock);
129
	tlb_refill_fail(pstate);
130
}
131
 
394 jermar 132
/** Process TLB Invalid Exception
133
 *
134
 * Process TLB Invalid Exception.
135
 *
136
 * @param pstate Interrupted register context.
137
 */
391 jermar 138
void tlb_invalid(struct exception_regdump *pstate)
139
{
396 jermar 140
	tlb_index_t index;
394 jermar 141
	__address badvaddr;
396 jermar 142
	entry_lo_t lo;
394 jermar 143
	pte_t *pte;
144
 
145
	badvaddr = cp0_badvaddr_read();
146
 
147
	/*
148
	 * Locate the faulting entry in TLB.
149
	 */
150
	tlbp();
396 jermar 151
	index.value = cp0_index_read();
394 jermar 152
 
153
	spinlock_lock(&VM->lock);	
154
 
155
	/*
156
	 * Fail if the entry is not in TLB.
157
	 */
396 jermar 158
	if (index.p) {
159
		printf("TLB entry not found.\n");
394 jermar 160
		goto fail;
396 jermar 161
	}
394 jermar 162
 
163
	pte = find_mapping_and_check(badvaddr);
164
	if (!pte)
165
		goto fail;
166
 
167
	/*
168
	 * Read the faulting TLB entry.
169
	 */
170
	tlbr();
171
 
172
	/*
173
	 * Record access to PTE.
174
	 */
175
	pte->a = 1;
176
 
177
	prepare_entry_lo(&lo, pte->g, pte->v, pte->d, pte->c, pte->pfn);
178
 
179
	/*
180
	 * The entry is to be updated in TLB.
181
	 */
182
	if ((badvaddr/PAGE_SIZE) % 2 == 0)
396 jermar 183
		cp0_entry_lo0_write(lo.value);
394 jermar 184
	else
396 jermar 185
		cp0_entry_lo1_write(lo.value);
394 jermar 186
	tlbwi();
187
 
188
	spinlock_unlock(&VM->lock);	
189
	return;
190
 
191
fail:
192
	spinlock_unlock(&VM->lock);
391 jermar 193
	tlb_invalid_fail(pstate);
194
}
195
 
394 jermar 196
/** Process TLB Modified Exception
197
 *
198
 * Process TLB Modified Exception.
199
 *
200
 * @param pstate Interrupted register context.
201
 */
391 jermar 202
void tlb_modified(struct exception_regdump *pstate)
203
{
396 jermar 204
	tlb_index_t index;
394 jermar 205
	__address badvaddr;
396 jermar 206
	entry_lo_t lo;
394 jermar 207
	pte_t *pte;
208
 
209
	badvaddr = cp0_badvaddr_read();
210
 
211
	/*
212
	 * Locate the faulting entry in TLB.
213
	 */
214
	tlbp();
396 jermar 215
	index.value = cp0_index_read();
394 jermar 216
 
217
	spinlock_lock(&VM->lock);	
218
 
219
	/*
220
	 * Fail if the entry is not in TLB.
221
	 */
396 jermar 222
	if (index.p) {
223
		printf("TLB entry not found.\n");
394 jermar 224
		goto fail;
396 jermar 225
	}
394 jermar 226
 
227
	pte = find_mapping_and_check(badvaddr);
228
	if (!pte)
229
		goto fail;
230
 
231
	/*
232
	 * Fail if the page is not writable.
233
	 */
234
	if (!pte->w)
235
		goto fail;
236
 
237
	/*
238
	 * Read the faulting TLB entry.
239
	 */
240
	tlbr();
241
 
242
	/*
243
	 * Record access and write to PTE.
244
	 */
245
	pte->a = 1;
246
	pte->d = 1;
247
 
248
	prepare_entry_lo(&lo, pte->g, pte->v, pte->w, pte->c, pte->pfn);
249
 
250
	/*
251
	 * The entry is to be updated in TLB.
252
	 */
253
	if ((badvaddr/PAGE_SIZE) % 2 == 0)
396 jermar 254
		cp0_entry_lo0_write(lo.value);
394 jermar 255
	else
396 jermar 256
		cp0_entry_lo1_write(lo.value);
394 jermar 257
	tlbwi();
258
 
259
	spinlock_unlock(&VM->lock);	
260
	return;
261
 
262
fail:
263
	spinlock_unlock(&VM->lock);
391 jermar 264
	tlb_modified_fail(pstate);
265
}
266
 
267
void tlb_refill_fail(struct exception_regdump *pstate)
268
{
324 palkovsky 269
	char *symbol = "";
270
	char *sym2 = "";
271
 
332 palkovsky 272
	char *s = get_symtab_entry(pstate->epc);
273
	if (s)
274
		symbol = s;
275
	s = get_symtab_entry(pstate->ra);
276
	if (s)
277
		sym2 = s;
391 jermar 278
	panic("%X: TLB Refill Exception at %X(%s<-%s)\n", cp0_badvaddr_read(), pstate->epc, symbol, sym2);
1 jermar 279
}
280
 
391 jermar 281
 
282
void tlb_invalid_fail(struct exception_regdump *pstate)
1 jermar 283
{
268 palkovsky 284
	char *symbol = "";
285
 
332 palkovsky 286
	char *s = get_symtab_entry(pstate->epc);
287
	if (s)
288
		symbol = s;
394 jermar 289
	panic("%X: TLB Invalid Exception at %X(%s)\n", cp0_badvaddr_read(), pstate->epc, symbol);
1 jermar 290
}
291
 
391 jermar 292
void tlb_modified_fail(struct exception_regdump *pstate)
389 jermar 293
{
294
	char *symbol = "";
295
 
296
	char *s = get_symtab_entry(pstate->epc);
297
	if (s)
298
		symbol = s;
394 jermar 299
	panic("%X: TLB Modified Exception at %X(%s)\n", cp0_badvaddr_read(), pstate->epc, symbol);
389 jermar 300
}
301
 
396 jermar 302
/** Invalidate TLB entries with specified ASID
303
 *
304
 * Invalidate TLB entries with specified ASID.
305
 *
306
 * @param asid ASID.
307
 */
308
void tlb_invalidate(asid_t asid)
1 jermar 309
{
396 jermar 310
	entry_hi_t hi;
130 decky 311
	pri_t pri;
396 jermar 312
	int i;	
130 decky 313
 
396 jermar 314
	ASSERT(asid != ASID_INVALID);
315
 
130 decky 316
	pri = cpu_priority_high();
317
 
396 jermar 318
	for (i = 0; i < TLB_SIZE; i++) {
319
		cp0_index_write(i);
320
		tlbr();
321
 
322
		hi.value = cp0_entry_hi_read();
323
		if (hi.asid == asid) {
324
			cp0_pagemask_write(TLB_PAGE_MASK_16K);
325
			cp0_entry_hi_write(0);
326
			cp0_entry_lo0_write(0);
327
			cp0_entry_lo1_write(0);
328
			tlbwi();
329
		}
330
	}
130 decky 331
 
332
	cpu_priority_restore(pri);
1 jermar 333
}
394 jermar 334
 
335
/** Try to find PTE for faulting address
336
 *
337
 * Try to find PTE for faulting address.
338
 * The VM->lock must be held on entry to this function.
339
 *
340
 * @param badvaddr Faulting virtual address.
341
 *
342
 * @return PTE on success, NULL otherwise.
343
 */
344
pte_t *find_mapping_and_check(__address badvaddr)
345
{
396 jermar 346
	entry_hi_t hi;
394 jermar 347
	pte_t *pte;
348
 
396 jermar 349
	hi.value = cp0_entry_hi_read();
394 jermar 350
 
351
	/*
352
	 * Handler cannot succeed if the ASIDs don't match.
353
	 */
396 jermar 354
	if (hi.asid != VM->asid) {
355
		printf("EntryHi.asid=%d, VM->asid=%d\n", hi.asid, VM->asid);
394 jermar 356
		return NULL;
396 jermar 357
	}
394 jermar 358
 
359
	/*
360
	 * Handler cannot succeed if badvaddr has no mapping.
361
	 */
362
	pte = find_mapping(badvaddr, 0);
396 jermar 363
	if (!pte) {
364
		printf("No such mapping.\n");
394 jermar 365
		return NULL;
396 jermar 366
	}
394 jermar 367
 
368
	/*
369
	 * Handler cannot succeed if the mapping is marked as invalid.
370
	 */
396 jermar 371
	if (!pte->v) {
372
		printf("Invalid mapping.\n");
394 jermar 373
		return NULL;
396 jermar 374
	}
394 jermar 375
 
376
	return pte;
377
}
378
 
396 jermar 379
void prepare_entry_lo(entry_lo_t *lo, bool g, bool v, bool d, int c, __address pfn)
394 jermar 380
{
381
	lo->g = g;
382
	lo->v = v;
383
	lo->d = d;
384
	lo->c = c;
385
	lo->pfn = pfn;
386
	lo->zero = 0;
387
}