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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since bfce7d9 was bfce7d9, checked in by Jakub Jermar <jakub@…>, 17 years ago

Do not print "Page fault.\n" if a mapping is not found during TLB refill.

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