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

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

fix segment register values, ppc32 works again (both w/ and w/o BAT)

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