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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c1b455e was 37e518b, checked in by Jiri Svoboda <jirik.svoboda@…>, 17 years ago

Bugfix: A ppc32 task would hang if it touched unmapped memory - was calling printf() with address-space mutex held.

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