60924cd4d5c2447ae744094bc833c7e4efd2bd3a
2 #include "ppcmmu/mmu.h"
3 #include "ppcmmu/mmuutil.h"
7 typedef unsigned long ULONG
;
13 0x00400 -- Instruction miss
14 0x10000 -- Entry point
16 0x20000 -- Physical map (PTE + Process Ptr + Address : 16 bytes)
18 4096 / 16 bytes = 256 entries per page
19 256 pages = 1Megabyte = 1 page table page
21 Setup by freeldr and used to build the kernel map, then used by the kernel
38 09 get first usable page
43 MmuPageCallback callback
;
44 typedef struct _MmuFreePage
{
46 struct _MmuFreePage
*next
;
48 typedef struct _MmuFreeTree
{
49 struct _MmuFreeTree
*next
;
51 typedef struct _MmuVsidTree
{
52 ppc_map_t
*leaves
[256];
54 typedef struct _MmuVsidInfo
{
56 struct _MmuVsidInfo
*next
;
57 MmuVsidTree
*tree
[256];
59 MmuFreePage
*FreeList
;
60 // Pages are allocated one by one until NextPage == RamSize >> PPC_PAGE_SHIFT
61 // Then we take only from the free list
62 int Clock
= 0, TreeAlloc
= 0;
63 paddr_t RamSize
, FirstUsablePage
, NextPage
;
64 MmuVsidTree
*NextTreePage
= 0;
65 MmuFreeTree
*FreeTree
;
66 MmuVsidInfo
*Segs
[16], *VsidHead
= 0;
68 extern void fmtout(const char *fmt
, ...);
69 int ptegreload(ppc_trap_frame_t
*frame
, vaddr_t addr
);
76 "lis 7,oldstack@ha\n\t"
77 "addi 7,7,oldstack@l\n\t"
84 "lis 7,oldstack@ha\n\t"
85 "addi 7,7,oldstack@l\n\t"
94 ".globl data_miss_finish_start\n"
95 "data_miss_finish_start:\n\t"
139 * lr, ctr, srr0, srr1, dsisr
142 ".globl data_miss_start\n\t"
143 ".globl data_miss_end\n\t"
144 "data_miss_start:\n\t"
199 "lis 5,data_miss_finish_start@ha\n\t"
200 "addi 5,5,data_miss_finish_start@l\n\t"
202 "lis 5,_mmumain@ha\n\t"
203 "addi 5,5,_mmumain@l\n\t"
209 extern int data_miss_end
, data_miss_start
;
211 int _mmumain(int action
, void *arg1
, void *arg2
, void *arg3
)
213 void (*fun
)(void *) = arg1
;
214 ppc_trap_frame_t
*trap_frame
= arg1
;
223 ret
= mmuaddpage(arg1
, (int)arg2
);
226 mmudelpage(arg1
, (int)arg2
);
229 mmusetvsid((int)arg1
, (int)arg2
, (int)arg3
);
232 /* Miss callback = arg1 */
237 mmugetpage(arg1
, (int)arg2
);
243 __asm__("mfmsr 3\n\t"
251 : : "r" (HTABORG
), "r" (arg2
), "r" (fun
));
255 mmusetramsize((paddr_t
)arg1
);
258 return FirstUsablePage
;
260 mmuallocvsid((int)arg1
, (int)arg2
);
263 mmufreevsid((int)arg1
, (int)arg2
);
266 if(!ptegreload(trap_frame
, trap_frame
->dar
))
268 __asm__("mfmsr 3\n\tori 3,3,0x30\n\tmtmsr 3\n\t");
273 if(!ptegreload(trap_frame
, trap_frame
->srr0
))
275 __asm__("mfmsr 3\n\tori 3,3,0x30\n\tmtmsr 3\n\t");
288 SetPhysByte(0x800003f8, c
);
291 void outstr(const char *str
)
293 while(*str
) outchar(*str
);
298 if(dig
< 10) outchar(dig
+ '0');
299 else outchar(dig
- 10 + 'A');
302 void outnum(unsigned long num
)
305 for( i
= 0; i
< 8; i
++ )
312 void fmtout(const char *str
, ...)
324 else if(str
[1] == 's')
326 outstr(va_arg(ap
, const char *));
330 outnum(va_arg(ap
, int));
343 void mmusetramsize(paddr_t ramsize
)
345 ppc_map_t
*last_map
= &PpcPageTable
[PPC_PAGE_NUMBER(ramsize
)];
349 FirstUsablePage
= (paddr_t
)last_map
;
350 NextPage
= PPC_PAGE_NUMBER(FirstUsablePage
);
359 for(i
= 0; i
< HTABSIZ
/ sizeof(int); i
++)
361 ((int *)HTABORG
)[i
] = 0;
364 for(target
= (int *)0x300, start
= &data_miss_start
; start
< &data_miss_end
; start
++, target
++)
366 SetPhys((paddr_t
)target
, *start
);
369 (&data_miss_start
)[50]++;
371 for(target
= (int *)0x400, start
= &data_miss_start
; start
< &data_miss_end
; start
++, target
++)
373 SetPhys((paddr_t
)target
, *start
);
377 ppc_map_t
*allocpage()
379 MmuFreePage
*FreePage
= 0;
381 if(NextPage
< PPC_PAGE_NUMBER(RamSize
)) {
382 return &PpcPageTable
[NextPage
++];
385 FreeList
= FreeList
->next
;
386 return ((ppc_map_t
*)FreePage
);
390 void freepage(ppc_map_t
*PagePtr
)
392 MmuFreePage
*FreePage
= (MmuFreePage
*)PagePtr
;
393 PagePtr
->proc
= PagePtr
->addr
= 0;
394 FreePage
->next
= FreeList
;
398 MmuVsidTree
*allocvsidtree()
402 MmuVsidTree
*result
= (MmuVsidTree
*)FreeTree
;
403 FreeTree
= FreeTree
->next
;
406 else if(TreeAlloc
>= 3 || !NextTreePage
)
408 ppc_map_t
*map
= allocpage();
409 NextTreePage
= (MmuVsidTree
*)PPC_PAGE_ADDR((map
- PpcPageTable
));
415 return &NextTreePage
[TreeAlloc
++];
419 void freevsidtree(MmuVsidTree
*tree
)
422 for(i
= 0; i
< 256; i
++)
424 freepage(tree
->leaves
[i
]);
425 MmuFreeTree
*NextFreeTree
= (MmuFreeTree
*)tree
;
426 NextFreeTree
->next
= FreeTree
;
427 FreeTree
= NextFreeTree
;
430 void *allocvsid(int vsid
)
432 ppc_map_t
*map
= allocpage();
435 map
->pte
.pteh
= map
->pte
.ptel
= 0;
436 info
= (MmuVsidInfo
*)PPC_PAGE_ADDR((map
- PpcPageTable
));
438 info
->next
= VsidHead
;
443 void mmuallocvsid(int vsid
, int mask
)
446 for(i
= 0; i
< 16; i
++)
449 allocvsid((vsid
<< 4) + i
);
453 MmuVsidInfo
*findvsid(int vsid
)
456 for(info
= VsidHead
; info
; info
= info
->next
)
458 if(info
->vsid
== vsid
) return info
;
463 void freevsid(int vsid
)
466 MmuVsidInfo
*info
= findvsid(vsid
);
468 ppc_map_t
*map
= &PpcPageTable
[PPC_PAGE_NUMBER((paddr_t
)info
)];
469 for(i
= 0; i
< 256; i
++)
472 freevsidtree(info
->tree
[i
]);
477 void mmufreevsid(int vsid
, int mask
)
480 for(i
= 0; i
< 16; i
++)
483 allocvsid((vsid
<< 4) + i
);
487 int mmuaddpage(ppc_map_info_t
*info
, int count
)
489 int i
, iva
= 0, vsid
, phys
, virt
;
491 int ptelo
, vsid_table_hi
, vsid_table_lo
;
493 MmuVsidInfo
*VsidInfo
;
494 MmuVsidTree
*VsidTree
;
496 for(i
= 0; i
< count
; i
++)
499 vsid
= ((info
[i
].addr
>> 28) & 15) | (info
[i
].proc
<< 4);
500 VsidInfo
= findvsid(vsid
);
502 if(!VsidInfo
) return -1;
504 ptehi
= (1 << 31) | (vsid
<< 7) | ((virt
>> 22) & 0x3f);
507 PagePtr
= &PpcPageTable
[PPC_PAGE_NUMBER(info
[i
].phys
)];
509 PagePtr
= allocpage();
516 phys
= PPC_PAGE_ADDR((PagePtr
- PpcPageTable
));
517 ptelo
= phys
& ~PPC_PAGE_MASK
;
519 /* Update page data */
520 PagePtr
->pte
.pteh
= ptehi
;
521 PagePtr
->pte
.ptel
= ptelo
;
522 PagePtr
->proc
= info
[i
].proc
;
523 PagePtr
->addr
= virt
;
525 vsid_table_hi
= virt
>> 20 & 255;
526 vsid_table_lo
= virt
>> 12 & 255;
528 if(!VsidInfo
->tree
[vsid_table_hi
])
529 VsidInfo
->tree
[vsid_table_hi
] = allocvsidtree();
530 VsidTree
= VsidInfo
->tree
[vsid_table_hi
];
531 if(!VsidTree
) return 0;
532 VsidTree
->leaves
[vsid_table_lo
] = PagePtr
;
534 __asm__("tlbie %0\n\tsync\n\tisync" : : "r" (iva
));
539 ppc_pteg_t
*PtegFromPage(ppc_map_t
*map
, int hfun
)
541 if(!map
->proc
&& !map
->addr
) return 0;
542 return &PpcHashedPTE
[PtegNumber(map
->addr
, hfun
)];
545 int PageMatch(vaddr_t addr
, ppc_pte_t pte
)
547 int vsid_pte
= (pte
.pteh
>> 7) & 15, api_pte
= pte
.pteh
& 63;
549 (((addr
>> 28) & 15) == vsid_pte
) &&
550 (((addr
>> 22) & 63) == api_pte
);
553 ppc_map_t
*mmuvirtmap(vaddr_t addr
, int vsid
)
555 int seg
= (addr
>> 28) & 15;
556 MmuVsidInfo
*seginfo
= Segs
[seg
];
557 MmuVsidTree
*segtree
= 0;
558 if(!seginfo
) return 0;
559 segtree
= seginfo
->tree
[(addr
>> 20) & 255];
560 if(!segtree
) return 0;
561 return segtree
->leaves
[(addr
>> 12) & 255];
564 void mmudelpage(ppc_map_info_t
*info
, int count
)
568 ppc_pteg_t
*PageEntry
;
569 ppc_pte_t ZeroPte
= { 0 };
571 for(i
= 0; i
< count
; i
++)
576 PagePtr
= &PpcPageTable
[ipa
];
577 info
[i
].proc
= PagePtr
->proc
;
578 info
[i
].addr
= PagePtr
->addr
;
582 PagePtr
= mmuvirtmap(info
[i
].proc
, info
[i
].addr
);
583 ipa
= PPC_PAGE_ADDR(PagePtr
- PpcPageTable
);
586 for(j
= 0; j
< 2; j
++)
588 PageEntry
= PtegFromPage(PagePtr
, j
);
589 for(k
= 0; k
< 8; k
++)
591 if(PageMatch(ipa
, PageEntry
->block
[k
]))
593 if(PageEntry
->block
[k
].ptel
& 0x100)
594 info
[i
].flags
|= MMU_PAGE_DIRTY
;
595 PageEntry
->block
[k
] = ZeroPte
;
600 __asm__("tlbie %0\n\tsync\n\tisync" : : "r" (info
[i
].addr
));
604 void mmugetpage(ppc_map_info_t
*info
, int count
)
609 for( i
= 0; i
< count
; i
++ )
611 if(!info
[i
].addr
&& !info
[i
].proc
)
613 PagePtr
= &((ppc_map_t
*)PAGETAB
)[info
[i
].phys
];
614 info
[i
].proc
= PagePtr
->proc
;
615 info
[i
].addr
= PagePtr
->addr
;
616 info
[i
].flags
= MMU_ALL_RW
;
618 vaddr_t addr
= info
[i
].addr
;
619 int vsid
= ((addr
>> 28) & 15) | (info
[i
].proc
<< 4);
620 PagePtr
= mmuvirtmap(info
[i
].addr
, vsid
);
625 info
[i
].phys
= PPC_PAGE_ADDR(PagePtr
- PpcPageTable
);
626 info
[i
].flags
= MMU_ALL_RW
; // HACK
632 void mmusetvsid(int start
, int end
, int vsid
)
635 for(i
= start
; i
< end
; i
++)
637 s_vsid
= (vsid
<< 4) | (i
& 15);
638 sr
= (GetSR(i
) & ~PPC_VSID_MASK
) | s_vsid
;
640 Segs
[i
] = findvsid(s_vsid
);
644 int ptegreload(ppc_trap_frame_t
*frame
, vaddr_t addr
)
646 int hfun
= (Clock
>> 3) & 1, ptegnum
= PtegNumber(addr
, hfun
);
647 int vsid
= GetSR((addr
>> 28) & 15) & PPC_VSID_MASK
;
648 ppc_map_t
*map
= mmuvirtmap(addr
, vsid
);
650 map
->pte
.pteh
= (map
->pte
.pteh
& ~64) | (hfun
<< 6);
651 PpcHashedPTE
[ptegnum
].block
[Clock
& 7] = map
->pte
;
653 fmtout("Reloading addr %x (phys %x) at %x[%x] (%x:%x)\r\n",
654 addr
, PPC_PAGE_ADDR(map
- PpcPageTable
), ptegnum
, Clock
& 15,
655 PpcHashedPTE
[ptegnum
].block
[Clock
&7].pteh
,
656 PpcHashedPTE
[ptegnum
].block
[Clock
&7].ptel
);
659 __asm__("tlbie %0\n\tsync\n\tisync" : : "r" (addr
));