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

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

cleanup the huge mess related to stacks, their sizes and locations
use two frames for kernel stacks by default on all platforms (to play it safe)

  • Property mode set to 100644
File size: 8.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 <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 = 42;
47
48/** Try to find PTE for faulting address
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 *
58 * @return PTE on success, NULL otherwise.
59 *
60 */
61static pte_t *find_mapping_and_check(as_t *as, uintptr_t badvaddr, int access,
62 istate_t *istate, int *pfrc)
63{
64 ASSERT(mutex_locked(&as->lock));
65
66 /*
67 * Check if the mapping exists in page tables.
68 */
69 pte_t *pte = page_mapping_find(as, badvaddr);
70 if ((pte) && (pte->present)) {
71 /*
72 * Mapping found in page tables.
73 * Immediately succeed.
74 */
75 return pte;
76 } else {
77 /*
78 * Mapping not found in page tables.
79 * Resort to higher-level page fault handler.
80 */
81 page_table_unlock(as, true);
82
83 int rc = as_page_fault(badvaddr, access, istate);
84 switch (rc) {
85 case AS_PF_OK:
86 /*
87 * The higher-level page fault handler succeeded,
88 * The mapping ought to be in place.
89 */
90 page_table_lock(as, true);
91 pte = page_mapping_find(as, badvaddr);
92 ASSERT((pte) && (pte->present));
93 *pfrc = 0;
94 return pte;
95 case AS_PF_DEFER:
96 page_table_lock(as, true);
97 *pfrc = rc;
98 return NULL;
99 case AS_PF_FAULT:
100 page_table_lock(as, true);
101 *pfrc = rc;
102 return NULL;
103 default:
104 panic("Unexpected rc (%d).", rc);
105 }
106 }
107}
108
109static void pht_refill_fail(uintptr_t badvaddr, istate_t *istate)
110{
111 fault_if_from_uspace(istate, "PHT Refill Exception on %p.",
112 (void *) badvaddr);
113 panic_memtrap(istate, PF_ACCESS_UNKNOWN, badvaddr,
114 "PHT Refill Exception.");
115}
116
117static void pht_insert(const uintptr_t vaddr, const pte_t *pte)
118{
119 uint32_t page = (vaddr >> 12) & 0xffff;
120 uint32_t api = (vaddr >> 22) & 0x3f;
121
122 uint32_t vsid = sr_get(vaddr);
123 uint32_t sdr1 = sdr1_get();
124
125 // FIXME: compute size of PHT exactly
126 phte_t *phte = (phte_t *) PA2KA(sdr1 & 0xffff0000);
127
128 /* Primary hash (xor) */
129 uint32_t h = 0;
130 uint32_t hash = vsid ^ page;
131 uint32_t base = (hash & 0x3ff) << 3;
132 uint32_t i;
133 bool found = false;
134
135 /* Find colliding PTE in PTEG */
136 for (i = 0; i < 8; i++) {
137 if ((phte[base + i].v)
138 && (phte[base + i].vsid == vsid)
139 && (phte[base + i].api == api)
140 && (phte[base + i].h == 0)) {
141 found = true;
142 break;
143 }
144 }
145
146 if (!found) {
147 /* Find unused PTE in PTEG */
148 for (i = 0; i < 8; i++) {
149 if (!phte[base + i].v) {
150 found = true;
151 break;
152 }
153 }
154 }
155
156 if (!found) {
157 /* Secondary hash (not) */
158 uint32_t base2 = (~hash & 0x3ff) << 3;
159
160 /* Find colliding PTE in PTEG */
161 for (i = 0; i < 8; i++) {
162 if ((phte[base2 + i].v)
163 && (phte[base2 + i].vsid == vsid)
164 && (phte[base2 + i].api == api)
165 && (phte[base2 + i].h == 1)) {
166 found = true;
167 base = base2;
168 h = 1;
169 break;
170 }
171 }
172
173 if (!found) {
174 /* Find unused PTE in PTEG */
175 for (i = 0; i < 8; i++) {
176 if (!phte[base2 + i].v) {
177 found = true;
178 base = base2;
179 h = 1;
180 break;
181 }
182 }
183 }
184
185 if (!found)
186 i = RANDI(seed) % 8;
187 }
188
189 phte[base + i].v = 1;
190 phte[base + i].vsid = vsid;
191 phte[base + i].h = h;
192 phte[base + i].api = api;
193 phte[base + i].rpn = pte->pfn;
194 phte[base + i].r = 0;
195 phte[base + i].c = 0;
196 phte[base + i].wimg = (pte->page_cache_disable ? WIMG_NO_CACHE : 0);
197 phte[base + i].pp = 2; // FIXME
198}
199
200/** Process Instruction/Data Storage Exception
201 *
202 * @param n Exception vector number.
203 * @param istate Interrupted register context.
204 *
205 */
206void pht_refill(unsigned int n, istate_t *istate)
207{
208 as_t *as = (AS == NULL) ? AS_KERNEL : AS;
209 uintptr_t badvaddr;
210
211 if (n == VECTOR_DATA_STORAGE)
212 badvaddr = istate->dar;
213 else
214 badvaddr = istate->pc;
215
216 page_table_lock(as, true);
217
218 int pfrc;
219 pte_t *pte = find_mapping_and_check(as, badvaddr,
220 PF_ACCESS_READ /* FIXME */, istate, &pfrc);
221
222 if (!pte) {
223 switch (pfrc) {
224 case AS_PF_FAULT:
225 page_table_unlock(as, true);
226 pht_refill_fail(badvaddr, istate);
227 return;
228 case AS_PF_DEFER:
229 /*
230 * The page fault came during copy_from_uspace()
231 * or copy_to_uspace().
232 */
233 page_table_unlock(as, true);
234 return;
235 default:
236 panic("Unexpected pfrc (%d).", pfrc);
237 }
238 }
239
240 /* Record access to PTE */
241 pte->accessed = 1;
242 pht_insert(badvaddr, pte);
243
244 page_table_unlock(as, true);
245}
246
247void tlb_refill(unsigned int n, istate_t *istate)
248{
249 uint32_t tlbmiss;
250 ptehi_t ptehi;
251 ptelo_t ptelo;
252
253 asm volatile (
254 "mfspr %[tlbmiss], 980\n"
255 "mfspr %[ptehi], 981\n"
256 "mfspr %[ptelo], 982\n"
257 : [tlbmiss] "=r" (tlbmiss),
258 [ptehi] "=r" (ptehi),
259 [ptelo] "=r" (ptelo)
260 );
261
262 uint32_t badvaddr = tlbmiss & 0xfffffffc;
263 uint32_t physmem = physmem_top();
264
265 if ((badvaddr < PA2KA(0)) || (badvaddr >= PA2KA(physmem)))
266 return; // FIXME
267
268 ptelo.rpn = KA2PA(badvaddr) >> 12;
269 ptelo.wimg = 0;
270 ptelo.pp = 2; // FIXME
271
272 uint32_t index = 0;
273 asm volatile (
274 "mtspr 981, %[ptehi]\n"
275 "mtspr 982, %[ptelo]\n"
276 "tlbld %[index]\n"
277 "tlbli %[index]\n"
278 : [index] "=r" (index)
279 : [ptehi] "r" (ptehi),
280 [ptelo] "r" (ptelo)
281 );
282}
283
284void tlb_arch_init(void)
285{
286 tlb_invalidate_all();
287}
288
289void tlb_invalidate_all(void)
290{
291 uint32_t index;
292
293 asm volatile (
294 "li %[index], 0\n"
295 "sync\n"
296
297 ".rept 64\n"
298 " tlbie %[index]\n"
299 " addi %[index], %[index], 0x1000\n"
300 ".endr\n"
301
302 "eieio\n"
303 "tlbsync\n"
304 "sync\n"
305 : [index] "=r" (index)
306 );
307}
308
309void tlb_invalidate_asid(asid_t asid)
310{
311 uint32_t sdr1 = sdr1_get();
312
313 // FIXME: compute size of PHT exactly
314 phte_t *phte = (phte_t *) PA2KA(sdr1 & 0xffff0000);
315
316 size_t i;
317 for (i = 0; i < 8192; i++) {
318 if ((phte[i].v) && (phte[i].vsid >= (asid << 4)) &&
319 (phte[i].vsid < ((asid << 4) + 16)))
320 phte[i].v = 0;
321 }
322
323 tlb_invalidate_all();
324}
325
326void tlb_invalidate_pages(asid_t asid, uintptr_t page, size_t cnt)
327{
328 // TODO
329 tlb_invalidate_all();
330}
331
332#define PRINT_BAT(name, ureg, lreg) \
333 asm volatile ( \
334 "mfspr %[upper], " #ureg "\n" \
335 "mfspr %[lower], " #lreg "\n" \
336 : [upper] "=r" (upper), \
337 [lower] "=r" (lower) \
338 ); \
339 \
340 mask = (upper & 0x1ffc) >> 2; \
341 if (upper & 3) { \
342 uint32_t tmp = mask; \
343 length = 128; \
344 \
345 while (tmp) { \
346 if ((tmp & 1) == 0) { \
347 printf("ibat[0]: error in mask\n"); \
348 break; \
349 } \
350 length <<= 1; \
351 tmp >>= 1; \
352 } \
353 } else \
354 length = 0; \
355 \
356 printf(name ": page=%#0" PRIx32 " frame=%#0" PRIx32 \
357 " length=%#0" PRIx32 " KB (mask=%#0" PRIx32 ")%s%s\n", \
358 upper & UINT32_C(0xffff0000), lower & UINT32_C(0xffff0000), \
359 length, mask, \
360 ((upper >> 1) & 1) ? " supervisor" : "", \
361 (upper & 1) ? " user" : "");
362
363void tlb_print(void)
364{
365 uint32_t sr;
366
367 for (sr = 0; sr < 16; sr++) {
368 uint32_t vsid = sr_get(sr << 28);
369
370 printf("sr[%02" PRIu32 "]: vsid=%#0" PRIx32 " (asid=%" PRIu32 ")"
371 "%s%s\n", sr, vsid & UINT32_C(0x00ffffff),
372 (vsid & UINT32_C(0x00ffffff)) >> 4,
373 ((vsid >> 30) & 1) ? " supervisor" : "",
374 ((vsid >> 29) & 1) ? " user" : "");
375 }
376
377 uint32_t upper;
378 uint32_t lower;
379 uint32_t mask;
380 uint32_t length;
381
382 PRINT_BAT("ibat[0]", 528, 529);
383 PRINT_BAT("ibat[1]", 530, 531);
384 PRINT_BAT("ibat[2]", 532, 533);
385 PRINT_BAT("ibat[3]", 534, 535);
386
387 PRINT_BAT("dbat[0]", 536, 537);
388 PRINT_BAT("dbat[1]", 538, 539);
389 PRINT_BAT("dbat[2]", 540, 541);
390 PRINT_BAT("dbat[3]", 542, 543);
391}
392
393/** @}
394 */
Note: See TracBrowser for help on using the repository browser.