Subversion Repositories HelenOS

Rev

Rev 1733 | Rev 1743 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1215 decky 1
/*
2
 * Copyright (C) 2006 Martin Decky
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
 
1730 decky 29
/** @addtogroup ppc32mm	
1702 cejka 30
 * @{
31
 */
32
/** @file
33
 */
34
 
1215 decky 35
#include <mm/tlb.h>
1730 decky 36
#include <arch/mm/tlb.h>
37
#include <arch/interrupt.h>
38
#include <mm/as.h>
39
#include <arch.h>
40
#include <print.h>
41
#include <symtab.h>
1215 decky 42
 
43
 
1730 decky 44
/** Try to find PTE for faulting address
1215 decky 45
 *
1730 decky 46
 * Try to find PTE for faulting address.
47
 * The as->lock must be held on entry to this function
48
 * if lock is true.
1215 decky 49
 *
1730 decky 50
 * @param as       Address space.
51
 * @param lock     Lock/unlock the address space.
52
 * @param badvaddr Faulting virtual address.
53
 * @param access   Access mode that caused the fault.
54
 * @param istate   Pointer to interrupted state.
55
 * @param pfrc     Pointer to variable where as_page_fault() return code will be stored.
56
 * @return         PTE on success, NULL otherwise.
57
 *
1215 decky 58
 */
1730 decky 59
static pte_t *find_mapping_and_check(as_t *as, bool lock, __address badvaddr, int access, istate_t *istate, int *pfrc)
60
{
61
	/*
62
	 * Check if the mapping exists in page tables.
63
	 */	
64
	pte_t *pte = page_mapping_find(as, badvaddr);
65
	if ((pte) && (pte->p)) {
66
		/*
67
		 * Mapping found in page tables.
68
		 * Immediately succeed.
69
		 */
70
		return pte;
71
	} else {
72
		int rc;
73
 
74
		/*
75
		 * Mapping not found in page tables.
76
		 * Resort to higher-level page fault handler.
77
		 */
78
		page_table_unlock(as, lock);
79
		switch (rc = as_page_fault(badvaddr, access, istate)) {
80
			case AS_PF_OK:
81
				/*
82
				 * The higher-level page fault handler succeeded,
83
				 * The mapping ought to be in place.
84
				 */
85
				page_table_lock(as, lock);
86
				pte = page_mapping_find(as, badvaddr);
87
				ASSERT((pte) && (pte->p));
88
				return pte;
89
			case AS_PF_DEFER:
90
				page_table_lock(as, lock);
91
				*pfrc = rc;
92
				return NULL;
93
			case AS_PF_FAULT:
94
				page_table_lock(as, lock);
95
				printf("Page fault.\n");
96
				*pfrc = rc;
97
				return NULL;
98
			default:
99
				panic("unexpected rc (%d)\n", rc);
100
		}	
101
	}
102
}
103
 
104
 
105
static void pht_refill_fail(__address badvaddr, istate_t *istate)
106
{
107
	char *symbol = "";
108
	char *sym2 = "";
109
 
110
	char *s = get_symtab_entry(istate->pc);
111
	if (s)
112
		symbol = s;
113
	s = get_symtab_entry(istate->lr);
114
	if (s)
115
		sym2 = s;
116
	panic("%p: PHT Refill Exception at %p (%s<-%s)\n", badvaddr, istate->pc, symbol, sym2);
117
}
118
 
119
 
120
static void pht_insert(const __address vaddr, const pfn_t pfn)
121
{
122
	__u32 page = (vaddr >> 12) & 0xffff;
123
	__u32 api = (vaddr >> 22) & 0x3f;
124
 
125
	__u32 vsid;
126
	asm volatile (
127
		"mfsrin %0, %1\n"
128
		: "=r" (vsid)
129
		: "r" (vaddr)
130
	);
131
 
132
	__u32 sdr1;
133
	asm volatile (
134
		"mfsdr1 %0\n"
135
		: "=r" (sdr1)
136
	);
137
	phte_t *phte = (phte_t *) PA2KA(sdr1 & 0xffff0000);
138
 
139
	/* Primary hash (xor) */
140
	__u32 h = 0;
141
	__u32 hash = vsid ^ page;
142
	__u32 base = (hash & 0x3ff) << 3;
143
	__u32 i;
144
	bool found = false;
145
 
146
	/* Find unused or colliding
147
	   PTE in PTEG */
148
	for (i = 0; i < 8; i++) {
149
		if ((!phte[base + i].v) || ((phte[base + i].vsid == vsid) && (phte[base + i].api == api))) {
150
			found = true;
151
			break;
152
		}
153
	}
154
 
155
	if (!found) {
156
		/* Secondary hash (not) */
157
		__u32 base2 = (~hash & 0x3ff) << 3;
158
 
159
		/* Find unused or colliding
160
		   PTE in PTEG */
161
		for (i = 0; i < 8; i++) {
162
			if ((!phte[base2 + i].v) || ((phte[base2 + i].vsid == vsid) && (phte[base2 + i].api == api))) {
163
				found = true;
164
				base = base2;
165
				h = 1;
166
				break;
167
			}
168
		}
169
 
170
		if (!found) {
171
			// TODO: A/C precedence groups
172
			i = page % 8;
173
		}
174
	}
175
 
176
	phte[base + i].v = 1;
177
	phte[base + i].vsid = vsid;
178
	phte[base + i].h = h;
179
	phte[base + i].api = api;
180
	phte[base + i].rpn = pfn;
181
	phte[base + i].r = 0;
182
	phte[base + i].c = 0;
183
	phte[base + i].pp = 2; // FIXME
184
}
185
 
186
 
187
static void pht_real_insert(const __address vaddr, const pfn_t pfn)
188
{
189
	__u32 page = (vaddr >> 12) & 0xffff;
190
	__u32 api = (vaddr >> 22) & 0x3f;
191
 
192
	__u32 vsid;
193
	asm volatile (
194
		"mfsrin %0, %1\n"
195
		: "=r" (vsid)
196
		: "r" (vaddr)
197
	);
198
 
199
	__u32 sdr1;
200
	asm volatile (
201
		"mfsdr1 %0\n"
202
		: "=r" (sdr1)
203
	);
204
	phte_t *phte_physical = (phte_t *) (sdr1 & 0xffff0000);
205
 
206
	/* Primary hash (xor) */
207
	__u32 h = 0;
208
	__u32 hash = vsid ^ page;
209
	__u32 base = (hash & 0x3ff) << 3;
210
	__u32 i;
211
	bool found = false;
212
 
213
	/* Find unused or colliding
214
	   PTE in PTEG */
215
	for (i = 0; i < 8; i++) {
216
		if ((!phte_physical[base + i].v) || ((phte_physical[base + i].vsid == vsid) && (phte_physical[base + i].api == api))) {
217
			found = true;
218
			break;
219
		}
220
	}
221
 
222
	if (!found) {
223
		/* Secondary hash (not) */
224
		__u32 base2 = (~hash & 0x3ff) << 3;
225
 
226
		/* Find unused or colliding
227
		   PTE in PTEG */
228
		for (i = 0; i < 8; i++) {
229
			if ((!phte_physical[base2 + i].v) || ((phte_physical[base2 + i].vsid == vsid) && (phte_physical[base2 + i].api == api))) {
230
				found = true;
231
				base = base2;
232
				h = 1;
233
				break;
234
			}
235
		}
236
 
237
		if (!found) {
238
			// TODO: A/C precedence groups
239
			i = page % 8;
240
		}
241
	}
242
 
243
	phte_physical[base + i].v = 1;
244
	phte_physical[base + i].vsid = vsid;
245
	phte_physical[base + i].h = h;
246
	phte_physical[base + i].api = api;
247
	phte_physical[base + i].rpn = pfn;
248
	phte_physical[base + i].r = 0;
249
	phte_physical[base + i].c = 0;
250
	phte_physical[base + i].pp = 2; // FIXME
251
}
252
 
253
 
254
/** Process Instruction/Data Storage Interrupt
255
 *
256
 * @param n Interrupt vector number.
257
 * @param istate Interrupted register context.
258
 *
259
 */
260
void pht_refill(int n, istate_t *istate)
261
{
262
	__address badvaddr;
263
	pte_t *pte;
264
	int pfrc;
265
	as_t *as;
266
	bool lock;
267
 
268
	if (AS == NULL) {
269
		as = AS_KERNEL;
270
		lock = false;
271
	} else {
272
		as = AS;
273
		lock = true;
274
	}
275
 
276
	if (n == VECTOR_DATA_STORAGE) {
277
		asm volatile (
278
			"mfdar %0\n"
279
			: "=r" (badvaddr)
280
		);
281
	} else
282
		badvaddr = istate->pc;
283
 
284
	page_table_lock(as, lock);
285
 
286
	pte = find_mapping_and_check(as, lock, badvaddr, PF_ACCESS_READ /* FIXME */, istate, &pfrc);
287
	if (!pte) {
288
		switch (pfrc) {
289
			case AS_PF_FAULT:
290
				goto fail;
291
				break;
292
			case AS_PF_DEFER:
293
				/*
294
		 		 * The page fault came during copy_from_uspace()
295
				 * or copy_to_uspace().
296
				 */
297
				page_table_unlock(as, lock);
298
				return;
299
			default:
300
				panic("Unexpected pfrc (%d)\n", pfrc);
301
		}
302
	}
303
 
304
	pte->a = 1; /* Record access to PTE */
305
	pht_insert(badvaddr, pte->pfn);
306
 
307
	page_table_unlock(as, lock);
308
	return;
309
 
310
fail:
311
	page_table_unlock(as, lock);
312
	pht_refill_fail(badvaddr, istate);
313
}
314
 
315
 
316
/** Process Instruction/Data Storage Interrupt in Real Mode
317
 *
318
 * @param n Interrupt vector number.
319
 * @param istate Interrupted register context.
320
 *
321
 */
322
bool pht_real_refill(int n, istate_t *istate)
323
{
324
	__address badvaddr;
325
 
326
	if (n == VECTOR_DATA_STORAGE) {
327
		asm volatile (
328
			"mfdar %0\n"
329
			: "=r" (badvaddr)
330
		);
331
	} else
332
		badvaddr = istate->pc;
333
 
334
	__u32 physmem;
335
	asm volatile (
336
		"mfsprg3 %0\n"
337
		: "=r" (physmem)
338
	);
339
 
340
	if ((badvaddr >= PA2KA(0)) && (badvaddr < PA2KA(physmem))) {
341
		pht_real_insert(badvaddr, KA2PA(badvaddr) >> 12);
342
		return true;
343
	}
344
 
345
	return false;
346
}
347
 
348
 
1215 decky 349
void tlb_arch_init(void)
350
{
1384 decky 351
	tlb_invalidate_all();
352
}
353
 
354
 
355
void tlb_invalidate_all(void)
356
{
1269 decky 357
	asm volatile (
1374 decky 358
		"tlbia\n"
1384 decky 359
		"tlbsync\n"
1269 decky 360
	);
1215 decky 361
}
362
 
363
 
1384 decky 364
void tlb_invalidate_asid(asid_t asid)
1328 decky 365
{
1730 decky 366
	// TODO
1384 decky 367
	tlb_invalidate_all();
1328 decky 368
}
369
 
1730 decky 370
 
1384 decky 371
void tlb_invalidate_pages(asid_t asid, __address page, count_t cnt)
372
{
1730 decky 373
	// TODO
1384 decky 374
	tlb_invalidate_all();
375
}
1328 decky 376
 
1384 decky 377
 
1736 decky 378
#define PRINT_BAT(name, ureg, lreg) \
379
	asm volatile ( \
380
		"mfspr %0," #ureg "\n" \
381
		"mfspr %1," #lreg "\n" \
382
		: "=r" (upper), "=r" (lower) \
383
	); \
384
	mask = (upper & 0x1ffc) >> 2; \
385
	if (upper & 3) { \
386
		__u32 tmp = mask; \
387
		length = 128; \
388
		while (tmp) { \
389
			if ((tmp & 1) == 0) { \
390
				printf("ibat[0]: error in mask\n"); \
391
				break; \
392
			} \
393
			length <<= 1; \
394
			tmp >>= 1; \
395
		} \
396
	} else \
397
		length = 0; \
398
	printf(name ": page=%.*p frame=%.*p length=%d KB (mask=%#x)%s%s\n", sizeof(upper) * 2, upper & 0xffff0000, sizeof(lower) * 2, lower & 0xffff0000, length, mask, ((upper >> 1) & 1) ? " supervisor" : "", (upper & 1) ? " user" : "");
399
 
400
 
1215 decky 401
void tlb_print(void)
402
{
1733 decky 403
	__u32 sr;
404
 
405
	for (sr = 0; sr < 16; sr++) {
406
		__u32 vsid;
407
		asm volatile (
408
			"mfsrin %0, %1\n"
409
			: "=r" (vsid)
410
			: "r" (sr << 28)
411
		);
1736 decky 412
		printf("vsid[%d]: VSID=%.*p (ASID=%d)%s%s\n", sr, sizeof(vsid) * 2, vsid & 0xffffff, (vsid & 0xffffff) >> 4, ((vsid >> 30) & 1) ? " supervisor" : "", ((vsid >> 29) & 1) ? " user" : "");
1733 decky 413
	}
1736 decky 414
 
415
	__u32 upper;
416
	__u32 lower;
417
	__u32 mask;
418
	__u32 length;
419
 
420
	PRINT_BAT("ibat[0]", 528, 529);
421
	PRINT_BAT("ibat[1]", 530, 531);
422
	PRINT_BAT("ibat[2]", 532, 533);
423
	PRINT_BAT("ibat[3]", 534, 535);
424
 
425
	PRINT_BAT("dbat[0]", 536, 537);
426
	PRINT_BAT("dbat[1]", 538, 539);
427
	PRINT_BAT("dbat[2]", 540, 541);
428
	PRINT_BAT("dbat[3]", 542, 543);
1215 decky 429
}
1702 cejka 430
 
1730 decky 431
/** @}
1702 cejka 432
 */