2 * Copyright (C) 2006 Martin Decky
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
29 /** @addtogroup ppc32mm
36 #include <arch/mm/tlb.h>
37 #include <arch/interrupt.h>
44 /** Try to find PTE for faulting address
46 * Try to find PTE for faulting address.
47 * The as->lock must be held on entry to this function
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.
59 static pte_t
*find_mapping_and_check(as_t
*as
, bool lock
, __address badvaddr
, int access
, istate_t
*istate
, int *pfrc
)
62 * Check if the mapping exists in page tables.
64 pte_t
*pte
= page_mapping_find(as
, badvaddr
);
65 if ((pte
) && (pte
->p
)) {
67 * Mapping found in page tables.
68 * Immediately succeed.
75 * Mapping not found in page tables.
76 * Resort to higher-level page fault handler.
78 page_table_unlock(as
, lock
);
79 switch (rc
= as_page_fault(badvaddr
, access
, istate
)) {
82 * The higher-level page fault handler succeeded,
83 * The mapping ought to be in place.
85 page_table_lock(as
, lock
);
86 pte
= page_mapping_find(as
, badvaddr
);
87 ASSERT((pte
) && (pte
->p
));
91 page_table_lock(as
, lock
);
95 page_table_lock(as
, lock
);
96 printf("Page fault.\n");
100 panic("unexpected rc (%d)\n", rc
);
106 static void pht_refill_fail(__address badvaddr
, istate_t
*istate
)
111 char *s
= get_symtab_entry(istate
->pc
);
114 s
= get_symtab_entry(istate
->lr
);
117 panic("%p: PHT Refill Exception at %p (%s<-%s)\n", badvaddr
, istate
->pc
, symbol
, sym2
);
121 static void pht_insert(const __address vaddr
, const pfn_t pfn
)
123 __u32 page
= (vaddr
>> 12) & 0xffff;
124 __u32 api
= (vaddr
>> 22) & 0x3f;
138 phte_t
*phte
= (phte_t
*) PA2KA(sdr1
& 0xffff0000);
140 /* Primary hash (xor) */
142 __u32 hash
= vsid
^ page
;
143 __u32 base
= (hash
& 0x3ff) << 3;
147 /* Find unused or colliding
149 for (i
= 0; i
< 8; i
++) {
150 if ((!phte
[base
+ i
].v
) || ((phte
[base
+ i
].vsid
== vsid
) && (phte
[base
+ i
].api
== api
))) {
157 /* Secondary hash (not) */
158 __u32 base2
= (~hash
& 0x3ff) << 3;
160 /* Find unused or colliding
162 for (i
= 0; i
< 8; i
++) {
163 if ((!phte
[base2
+ i
].v
) || ((phte
[base2
+ i
].vsid
== vsid
) && (phte
[base2
+ i
].api
== api
))) {
172 // TODO: A/C precedence groups
177 phte
[base
+ i
].v
= 1;
178 phte
[base
+ i
].vsid
= vsid
;
179 phte
[base
+ i
].h
= h
;
180 phte
[base
+ i
].api
= api
;
181 phte
[base
+ i
].rpn
= pfn
;
182 phte
[base
+ i
].r
= 0;
183 phte
[base
+ i
].c
= 0;
184 phte
[base
+ i
].pp
= 2; // FIXME
188 static void pht_real_insert(const __address vaddr
, const pfn_t pfn
)
190 __u32 page
= (vaddr
>> 12) & 0xffff;
191 __u32 api
= (vaddr
>> 22) & 0x3f;
205 phte_t
*phte_physical
= (phte_t
*) (sdr1
& 0xffff0000);
207 /* Primary hash (xor) */
209 __u32 hash
= vsid
^ page
;
210 __u32 base
= (hash
& 0x3ff) << 3;
214 /* Find unused or colliding
216 for (i
= 0; i
< 8; i
++) {
217 if ((!phte_physical
[base
+ i
].v
) || ((phte_physical
[base
+ i
].vsid
== vsid
) && (phte_physical
[base
+ i
].api
== api
))) {
224 /* Secondary hash (not) */
225 __u32 base2
= (~hash
& 0x3ff) << 3;
227 /* Find unused or colliding
229 for (i
= 0; i
< 8; i
++) {
230 if ((!phte_physical
[base2
+ i
].v
) || ((phte_physical
[base2
+ i
].vsid
== vsid
) && (phte_physical
[base2
+ i
].api
== api
))) {
239 // TODO: A/C precedence groups
244 phte_physical
[base
+ i
].v
= 1;
245 phte_physical
[base
+ i
].vsid
= vsid
;
246 phte_physical
[base
+ i
].h
= h
;
247 phte_physical
[base
+ i
].api
= api
;
248 phte_physical
[base
+ i
].rpn
= pfn
;
249 phte_physical
[base
+ i
].r
= 0;
250 phte_physical
[base
+ i
].c
= 0;
251 phte_physical
[base
+ i
].pp
= 2; // FIXME
255 /** Process Instruction/Data Storage Interrupt
257 * @param n Interrupt vector number.
258 * @param istate Interrupted register context.
261 void pht_refill(int n
, istate_t
*istate
)
277 if (n
== VECTOR_DATA_STORAGE
) {
283 badvaddr
= istate
->pc
;
285 page_table_lock(as
, lock
);
287 pte
= find_mapping_and_check(as
, lock
, badvaddr
, PF_ACCESS_READ
/* FIXME */, istate
, &pfrc
);
295 * The page fault came during copy_from_uspace()
296 * or copy_to_uspace().
298 page_table_unlock(as
, lock
);
301 panic("Unexpected pfrc (%d)\n", pfrc
);
305 pte
->a
= 1; /* Record access to PTE */
306 pht_insert(badvaddr
, pte
->pfn
);
308 page_table_unlock(as
, lock
);
312 page_table_unlock(as
, lock
);
313 pht_refill_fail(badvaddr
, istate
);
317 /** Process Instruction/Data Storage Interrupt in Real Mode
319 * @param n Interrupt vector number.
320 * @param istate Interrupted register context.
323 bool pht_real_refill(int n
, istate_t
*istate
)
327 if (n
== VECTOR_DATA_STORAGE
) {
333 badvaddr
= istate
->pc
;
341 if ((badvaddr
>= PA2KA(0)) && (badvaddr
< PA2KA(physmem
))) {
342 pht_real_insert(badvaddr
, KA2PA(badvaddr
) >> 12);
350 void tlb_arch_init(void)
352 tlb_invalidate_all();
356 void tlb_invalidate_all(void)
365 void tlb_invalidate_asid(asid_t asid
)
368 tlb_invalidate_all();
372 void tlb_invalidate_pages(asid_t asid
, __address page
, count_t cnt
)
375 tlb_invalidate_all();
379 #define PRINT_BAT(name, ureg, lreg) \
381 "mfspr %0," #ureg "\n" \
382 "mfspr %1," #lreg "\n" \
383 : "=r" (upper), "=r" (lower) \
385 mask = (upper & 0x1ffc) >> 2; \
390 if ((tmp & 1) == 0) { \
391 printf("ibat[0]: error in mask\n"); \
399 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" : "");
406 for (sr
= 0; sr
< 16; sr
++) {
413 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" : "");
421 PRINT_BAT("ibat[0]", 528, 529);
422 PRINT_BAT("ibat[1]", 530, 531);
423 PRINT_BAT("ibat[2]", 532, 533);
424 PRINT_BAT("ibat[3]", 534, 535);
426 PRINT_BAT("dbat[0]", 536, 537);
427 PRINT_BAT("dbat[1]", 538, 539);
428 PRINT_BAT("dbat[2]", 540, 541);
429 PRINT_BAT("dbat[3]", 542, 543);