source: mainline/kernel/arch/ppc32/src/mm/tlb.c@ 7e752b2

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 7e752b2 was 7e752b2, checked in by Martin Decky <martin@…>, 15 years ago
  • correct printf() formatting strings and corresponding arguments
  • minor cstyle changes and other small fixes
  • Property mode set to 100644
File size: 11.2 KB
Line 
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
29/** @addtogroup ppc32mm
30 * @{
31 */
32/** @file
33 */
34
35#include <mm/tlb.h>
36#include <arch/mm/tlb.h>
37#include <arch/interrupt.h>
38#include <interrupt.h>
39#include <mm/as.h>
40#include <mm/page.h>
41#include <arch.h>
42#include <print.h>
43#include <macros.h>
44#include <symtab.h>
45
46static unsigned int seed = 10;
47static unsigned int seed_real
48 __attribute__ ((section("K_UNMAPPED_DATA_START"))) = 42;
49
50/** Try to find PTE for faulting address
51 *
52 * @param as Address space.
53 * @param lock Lock/unlock the address space.
54 * @param badvaddr Faulting virtual address.
55 * @param access Access mode that caused the fault.
56 * @param istate Pointer to interrupted state.
57 * @param pfrc Pointer to variable where as_page_fault() return code
58 * will be stored.
59 *
60 * @return PTE on success, NULL otherwise.
61 *
62 */
63static pte_t *find_mapping_and_check(as_t *as, uintptr_t badvaddr, int access,
64 istate_t *istate, int *pfrc)
65{
66 ASSERT(mutex_locked(&as->lock));
67
68 /*
69 * Check if the mapping exists in page tables.
70 */
71 pte_t *pte = page_mapping_find(as, badvaddr);
72 if ((pte) && (pte->present)) {
73 /*
74 * Mapping found in page tables.
75 * Immediately succeed.
76 */
77 return pte;
78 } else {
79 /*
80 * Mapping not found in page tables.
81 * Resort to higher-level page fault handler.
82 */
83 page_table_unlock(as, true);
84
85 int rc = as_page_fault(badvaddr, access, istate);
86 switch (rc) {
87 case AS_PF_OK:
88 /*
89 * The higher-level page fault handler succeeded,
90 * The mapping ought to be in place.
91 */
92 page_table_lock(as, true);
93 pte = page_mapping_find(as, badvaddr);
94 ASSERT((pte) && (pte->present));
95 *pfrc = 0;
96 return pte;
97 case AS_PF_DEFER:
98 page_table_lock(as, true);
99 *pfrc = rc;
100 return NULL;
101 case AS_PF_FAULT:
102 page_table_lock(as, true);
103 *pfrc = rc;
104 return NULL;
105 default:
106 panic("Unexpected rc (%d).", rc);
107 }
108 }
109}
110
111static void pht_refill_fail(uintptr_t badvaddr, istate_t *istate)
112{
113 fault_if_from_uspace(istate, "PHT Refill Exception on %p.",
114 (void *) badvaddr);
115 panic_memtrap(istate, PF_ACCESS_UNKNOWN, badvaddr,
116 "PHT Refill Exception.");
117}
118
119static void pht_insert(const uintptr_t vaddr, const pte_t *pte)
120{
121 uint32_t page = (vaddr >> 12) & 0xffff;
122 uint32_t api = (vaddr >> 22) & 0x3f;
123
124 uint32_t vsid = sr_get(vaddr);
125 uint32_t sdr1 = sdr1_get();
126
127 // FIXME: compute size of PHT exactly
128 phte_t *phte = (phte_t *) PA2KA(sdr1 & 0xffff0000);
129
130 /* Primary hash (xor) */
131 uint32_t h = 0;
132 uint32_t hash = vsid ^ page;
133 uint32_t base = (hash & 0x3ff) << 3;
134 uint32_t i;
135 bool found = false;
136
137 /* Find colliding PTE in PTEG */
138 for (i = 0; i < 8; i++) {
139 if ((phte[base + i].v)
140 && (phte[base + i].vsid == vsid)
141 && (phte[base + i].api == api)
142 && (phte[base + i].h == 0)) {
143 found = true;
144 break;
145 }
146 }
147
148 if (!found) {
149 /* Find unused PTE in PTEG */
150 for (i = 0; i < 8; i++) {
151 if (!phte[base + i].v) {
152 found = true;
153 break;
154 }
155 }
156 }
157
158 if (!found) {
159 /* Secondary hash (not) */
160 uint32_t base2 = (~hash & 0x3ff) << 3;
161
162 /* Find colliding PTE in PTEG */
163 for (i = 0; i < 8; i++) {
164 if ((phte[base2 + i].v)
165 && (phte[base2 + i].vsid == vsid)
166 && (phte[base2 + i].api == api)
167 && (phte[base2 + i].h == 1)) {
168 found = true;
169 base = base2;
170 h = 1;
171 break;
172 }
173 }
174
175 if (!found) {
176 /* Find unused PTE in PTEG */
177 for (i = 0; i < 8; i++) {
178 if (!phte[base2 + i].v) {
179 found = true;
180 base = base2;
181 h = 1;
182 break;
183 }
184 }
185 }
186
187 if (!found)
188 i = RANDI(seed) % 8;
189 }
190
191 phte[base + i].v = 1;
192 phte[base + i].vsid = vsid;
193 phte[base + i].h = h;
194 phte[base + i].api = api;
195 phte[base + i].rpn = pte->pfn;
196 phte[base + i].r = 0;
197 phte[base + i].c = 0;
198 phte[base + i].wimg = (pte->page_cache_disable ? WIMG_NO_CACHE : 0);
199 phte[base + i].pp = 2; // FIXME
200}
201
202/** Process Instruction/Data Storage Exception
203 *
204 * @param n Exception vector number.
205 * @param istate Interrupted register context.
206 *
207 */
208void pht_refill(unsigned int n, istate_t *istate)
209{
210 as_t *as = (AS == NULL) ? AS_KERNEL : AS;
211 uintptr_t badvaddr;
212
213 if (n == VECTOR_DATA_STORAGE)
214 badvaddr = istate->dar;
215 else
216 badvaddr = istate->pc;
217
218 page_table_lock(as, true);
219
220 int pfrc;
221 pte_t *pte = find_mapping_and_check(as, badvaddr,
222 PF_ACCESS_READ /* FIXME */, istate, &pfrc);
223
224 if (!pte) {
225 switch (pfrc) {
226 case AS_PF_FAULT:
227 goto fail;
228 break;
229 case AS_PF_DEFER:
230 /*
231 * The page fault came during copy_from_uspace()
232 * or copy_to_uspace().
233 */
234 page_table_unlock(as, true);
235 return;
236 default:
237 panic("Unexpected pfrc (%d).", pfrc);
238 }
239 }
240
241 /* Record access to PTE */
242 pte->accessed = 1;
243 pht_insert(badvaddr, pte);
244
245 page_table_unlock(as, true);
246 return;
247
248fail:
249 page_table_unlock(as, true);
250 pht_refill_fail(badvaddr, istate);
251}
252
253/** Process Instruction/Data Storage Exception in Real Mode
254 *
255 * @param n Exception vector number.
256 * @param istate Interrupted register context.
257 *
258 */
259bool pht_refill_real(unsigned int n, istate_t *istate)
260{
261 uintptr_t badvaddr;
262
263 if (n == VECTOR_DATA_STORAGE)
264 badvaddr = istate->dar;
265 else
266 badvaddr = istate->pc;
267
268 uint32_t physmem = physmem_top();
269
270 if ((badvaddr < PA2KA(0)) || (badvaddr >= PA2KA(physmem)))
271 return false;
272
273 uint32_t page = (badvaddr >> 12) & 0xffff;
274 uint32_t api = (badvaddr >> 22) & 0x3f;
275
276 uint32_t vsid = sr_get(badvaddr);
277 uint32_t sdr1 = sdr1_get();
278
279 // FIXME: compute size of PHT exactly
280 phte_t *phte_real = (phte_t *) (sdr1 & 0xffff0000);
281
282 /* Primary hash (xor) */
283 uint32_t h = 0;
284 uint32_t hash = vsid ^ page;
285 uint32_t base = (hash & 0x3ff) << 3;
286 uint32_t i;
287 bool found = false;
288
289 /* Find colliding PTE in PTEG */
290 for (i = 0; i < 8; i++) {
291 if ((phte_real[base + i].v)
292 && (phte_real[base + i].vsid == vsid)
293 && (phte_real[base + i].api == api)
294 && (phte_real[base + i].h == 0)) {
295 found = true;
296 break;
297 }
298 }
299
300 if (!found) {
301 /* Find unused PTE in PTEG */
302 for (i = 0; i < 8; i++) {
303 if (!phte_real[base + i].v) {
304 found = true;
305 break;
306 }
307 }
308 }
309
310 if (!found) {
311 /* Secondary hash (not) */
312 uint32_t base2 = (~hash & 0x3ff) << 3;
313
314 /* Find colliding PTE in PTEG */
315 for (i = 0; i < 8; i++) {
316 if ((phte_real[base2 + i].v)
317 && (phte_real[base2 + i].vsid == vsid)
318 && (phte_real[base2 + i].api == api)
319 && (phte_real[base2 + i].h == 1)) {
320 found = true;
321 base = base2;
322 h = 1;
323 break;
324 }
325 }
326
327 if (!found) {
328 /* Find unused PTE in PTEG */
329 for (i = 0; i < 8; i++) {
330 if (!phte_real[base2 + i].v) {
331 found = true;
332 base = base2;
333 h = 1;
334 break;
335 }
336 }
337 }
338
339 if (!found) {
340 /* Use secondary hash to avoid collisions
341 with usual PHT refill handler. */
342 i = RANDI(seed_real) % 8;
343 base = base2;
344 h = 1;
345 }
346 }
347
348 phte_real[base + i].v = 1;
349 phte_real[base + i].vsid = vsid;
350 phte_real[base + i].h = h;
351 phte_real[base + i].api = api;
352 phte_real[base + i].rpn = KA2PA(badvaddr) >> 12;
353 phte_real[base + i].r = 0;
354 phte_real[base + i].c = 0;
355 phte_real[base + i].wimg = 0;
356 phte_real[base + i].pp = 2; // FIXME
357
358 return true;
359}
360
361/** Process ITLB/DTLB Miss Exception in Real Mode
362 *
363 *
364 */
365void tlb_refill_real(unsigned int n, uint32_t tlbmiss, ptehi_t ptehi,
366 ptelo_t ptelo, istate_t *istate)
367{
368 uint32_t badvaddr = tlbmiss & 0xfffffffc;
369 uint32_t physmem = physmem_top();
370
371 if ((badvaddr < PA2KA(0)) || (badvaddr >= PA2KA(physmem)))
372 return; // FIXME
373
374 ptelo.rpn = KA2PA(badvaddr) >> 12;
375 ptelo.wimg = 0;
376 ptelo.pp = 2; // FIXME
377
378 uint32_t index = 0;
379 asm volatile (
380 "mtspr 981, %[ptehi]\n"
381 "mtspr 982, %[ptelo]\n"
382 "tlbld %[index]\n"
383 "tlbli %[index]\n"
384 : [index] "=r" (index)
385 : [ptehi] "r" (ptehi),
386 [ptelo] "r" (ptelo)
387 );
388}
389
390void tlb_arch_init(void)
391{
392 tlb_invalidate_all();
393}
394
395void tlb_invalidate_all(void)
396{
397 uint32_t index;
398
399 asm volatile (
400 "li %[index], 0\n"
401 "sync\n"
402
403 ".rept 64\n"
404 " tlbie %[index]\n"
405 " addi %[index], %[index], 0x1000\n"
406 ".endr\n"
407
408 "eieio\n"
409 "tlbsync\n"
410 "sync\n"
411 : [index] "=r" (index)
412 );
413}
414
415void tlb_invalidate_asid(asid_t asid)
416{
417 uint32_t sdr1 = sdr1_get();
418
419 // FIXME: compute size of PHT exactly
420 phte_t *phte = (phte_t *) PA2KA(sdr1 & 0xffff0000);
421
422 size_t i;
423 for (i = 0; i < 8192; i++) {
424 if ((phte[i].v) && (phte[i].vsid >= (asid << 4)) &&
425 (phte[i].vsid < ((asid << 4) + 16)))
426 phte[i].v = 0;
427 }
428
429 tlb_invalidate_all();
430}
431
432void tlb_invalidate_pages(asid_t asid, uintptr_t page, size_t cnt)
433{
434 // TODO
435 tlb_invalidate_all();
436}
437
438#define PRINT_BAT(name, ureg, lreg) \
439 asm volatile ( \
440 "mfspr %[upper], " #ureg "\n" \
441 "mfspr %[lower], " #lreg "\n" \
442 : [upper] "=r" (upper), \
443 [lower] "=r" (lower) \
444 ); \
445 \
446 mask = (upper & 0x1ffc) >> 2; \
447 if (upper & 3) { \
448 uint32_t tmp = mask; \
449 length = 128; \
450 \
451 while (tmp) { \
452 if ((tmp & 1) == 0) { \
453 printf("ibat[0]: error in mask\n"); \
454 break; \
455 } \
456 length <<= 1; \
457 tmp >>= 1; \
458 } \
459 } else \
460 length = 0; \
461 \
462 printf(name ": page=%#0" PRIx32 " frame=%#0" PRIx32 \
463 " length=%#0" PRIx32 " KB (mask=%#0" PRIx32 ")%s%s\n", \
464 upper & UINT32_C(0xffff0000), lower & UINT32_C(0xffff0000), \
465 length, mask, \
466 ((upper >> 1) & 1) ? " supervisor" : "", \
467 (upper & 1) ? " user" : "");
468
469void tlb_print(void)
470{
471 uint32_t sr;
472
473 for (sr = 0; sr < 16; sr++) {
474 uint32_t vsid = sr_get(sr << 28);
475
476 printf("sr[%02" PRIu32 "]: vsid=%#0" PRIx32 " (asid=%" PRIu32 ")"
477 "%s%s\n", sr, vsid & UINT32_C(0x00ffffff),
478 (vsid & UINT32_C(0x00ffffff)) >> 4,
479 ((vsid >> 30) & 1) ? " supervisor" : "",
480 ((vsid >> 29) & 1) ? " user" : "");
481 }
482
483 uint32_t upper;
484 uint32_t lower;
485 uint32_t mask;
486 uint32_t length;
487
488 PRINT_BAT("ibat[0]", 528, 529);
489 PRINT_BAT("ibat[1]", 530, 531);
490 PRINT_BAT("ibat[2]", 532, 533);
491 PRINT_BAT("ibat[3]", 534, 535);
492
493 PRINT_BAT("dbat[0]", 536, 537);
494 PRINT_BAT("dbat[1]", 538, 539);
495 PRINT_BAT("dbat[2]", 540, 541);
496 PRINT_BAT("dbat[3]", 542, 543);
497}
498
499/** @}
500 */
Note: See TracBrowser for help on using the repository browser.