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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5954241 was 5954241, checked in by Martin Decky <martin@…>, 15 years ago

fix exception handler prototypes

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