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 #define MMU_ADDR_RESERVED ((vaddr_t)-2)
45 MmuTrapHandler callback
[0x30];
46 typedef struct _MmuFreePage
{
48 struct _MmuFreePage
*next
;
50 typedef struct _MmuFreeTree
{
51 struct _MmuFreeTree
*next
;
53 typedef struct _MmuVsidTree
{
54 ppc_map_t
*leaves
[256];
56 typedef struct _MmuVsidInfo
{
58 struct _MmuVsidInfo
*next
;
59 MmuVsidTree
*tree
[256];
61 MmuFreePage
*FreeList
= 0;
62 // Pages are allocated one by one until NextPage == RamSize >> PPC_PAGE_SHIFT
63 // Then we take only from the free list
64 int Clock
= 0, TreeAlloc
= 0, GdbAttach
= 0, Booted
= 0, Vsid
[16];
65 paddr_t RamSize
, FirstUsablePage
, NextPage
;
66 MmuVsidTree
*NextTreePage
= 0;
67 MmuFreeTree
*FreeTree
;
68 MmuVsidInfo
*Segs
[16], *VsidHead
= 0;
70 extern void fmtout(const char *fmt
, ...);
72 int ptegreload(ppc_trap_frame_t
*frame
, vaddr_t addr
);
73 void SerialSetUp(int deviceType
, void *deviceAddr
, int baud
);
74 int SerialInterrupt(int n
, ppc_trap_frame_t
*tf
);
75 void TakeException(int n
, ppc_trap_frame_t
*tf
);
76 int mmuisfreepage(paddr_t pageno
);
77 void copy(void *t
, void *s
, int b
);
80 void trapcallback(int action
, ppc_trap_frame_t
*trap_frame
);
82 int _mmumain(int action
, void *arg1
, void *arg2
, void *arg3
, void *tf
)
84 ppc_trap_frame_t
*trap_frame
= (action
>= 0x100) ? tf
: arg1
;
91 if(!ptegreload(trap_frame
, trap_frame
->dar
))
93 trapcallback(action
, trap_frame
);
97 if(!ptegreload(trap_frame
, trap_frame
->srr0
))
99 trapcallback(action
, trap_frame
);
104 /* EE -- Try to get a serial interrupt if debugging enabled, then fall
105 * back to primary handler
107 if (!SerialInterrupt(action
, trap_frame
) && callback
[action
])
109 trapcallback(action
, trap_frame
);
121 trapcallback(action
, trap_frame
);
127 trap_frame
->srr1
|= 0x8000;
130 ret
= mmuaddpage(arg1
, (int)arg2
);
133 mmudelpage(arg1
, (int)arg2
);
136 mmusetvsid((int)arg1
, (int)arg2
, (int)arg3
);
139 ret
= (int)callback
[(int)arg1
];
140 callback
[(int)arg1
] = (MmuTrapHandler
)arg2
;
143 mmugetpage(arg1
, (int)arg2
);
149 callkernel(arg1
, arg2
);
152 mmusetramsize((paddr_t
)arg1
);
155 return FirstUsablePage
;
157 mmuallocvsid((int)arg1
, (int)arg2
);
160 mmufreevsid((int)arg1
, (int)arg2
);
166 copy(trap_frame
, (void *)0xf040, sizeof(*trap_frame
));
167 __asm__("mr 1,%0\n\tb trap_finish_start" : : "r"
168 (((int)trap_frame
) - 16));
175 SerialSetUp((int)arg1
, arg2
, 9600);
178 TakeException((int)arg1
, trap_frame
);
185 /* Restore bats when we were called voluntarily. We may not get a chance
186 * to do this after returning.
188 * At this point, we're in address space that matches physical space.
189 * We turn off mapping, restore bats, then let rfi switch us back to where
195 __asm__("mfmsr %0" : "=r" (tmp
));
197 __asm__("mtmsr %0" : : "r" (tmp
));
199 for(i
= 0; i
< 4; i
++) {
200 SetBat(i
, 0, GetPhys(0xf000 + i
* 16), GetPhys(0xf004 + i
* 16));
201 SetBat(i
, 1, GetPhys(0xf008 + i
* 16), GetPhys(0xf00c + i
* 16));
208 void trapcallback(int action
, ppc_trap_frame_t
*trap_frame
)
210 if ((paddr_t
)callback
[action
] < PAGETAB
)
211 callback
[action
](action
, trap_frame
);
214 int framecopy
= 0xf040;
215 copy((void *)framecopy
, trap_frame
, sizeof(*trap_frame
));
216 trap_frame
->srr0
= (int)callback
[action
];
217 trap_frame
->srr1
&= 0x7fff;
218 trap_frame
->gpr
[3] = action
;
219 trap_frame
->gpr
[4] = framecopy
;
220 __asm__("mr 1,%0\n\tsubi 1,1,16\n\tb trap_finish_start" : : "r" (trap_frame
));
226 SetPhysByte(0x800003f8, c
);
229 void copy(void *target
, void *src
, int bytes
)
231 while(bytes
--) *((char *)target
++) = *((char *)src
++);
234 void outstr(const char *str
)
236 while(*str
) outchar(*str
);
241 if(dig
< 10) outchar(dig
+ '0');
242 else outchar(dig
- 10 + 'A');
245 void outnum(unsigned long num
)
248 for( i
= 0; i
< 8; i
++ )
255 void fmtout(const char *str
, ...)
267 else if(str
[1] == 's')
269 outstr(va_arg(ap
, const char *));
273 outnum(va_arg(ap
, int));
286 void mmusetramsize(paddr_t ramsize
)
288 ppc_map_t
*last_map
= &PpcPageTable
[PPC_PAGE_NUMBER(ramsize
)];
292 FirstUsablePage
= (paddr_t
)last_map
;
293 NextPage
= PPC_PAGE_NUMBER(FirstUsablePage
) + 1;
297 int ignore(int trapCode
, ppc_trap_frame_t
*trap
)
302 int fpenable(int trapCode
, ppc_trap_frame_t
*trap
)
309 extern int trap_start
[], trap_end
[];
310 void copy_trap_handler(int trap
)
313 paddr_t targetArea
= trap
* 0x100;
315 /* Set target addr */
316 trap_end
[0] = (int)_mmumain
;
318 for (i
= 0; i
<= trap_end
- trap_start
; i
++)
320 SetPhys(targetArea
+ (i
* sizeof(int)), trap_start
[i
]);
328 for(i
= 0; i
< HTABSIZ
/ sizeof(int); i
++)
330 ((int *)HTABORG
)[i
] = 0;
333 /* Default to hang on unknown exception */
334 for(i
= 0; i
< 30; i
++)
336 callback
[i
] = (MmuTrapHandler
)TakeException
;
337 if (i
!= 1) /* Preserve reset handler */
338 copy_trap_handler(i
);
341 /* Serial Interrupt */
342 callback
[5] = 0; /* Do nothing until the user asks */
344 /* Program Exception */
345 callback
[6] = (MmuTrapHandler
)TakeException
;
347 /* Floating point exception */
348 callback
[8] = fpenable
;
350 /* Ignore decrementer and EE */
351 callback
[9] = ignore
;
354 callback
[0x20] = (MmuTrapHandler
)TakeException
;
357 ppc_map_t
*allocpage()
359 MmuFreePage
*FreePage
= 0;
363 if ((void *)FreeList
== (void *)PpcPageTable
)
365 fmtout("Problem! FreeList: page 0 is free\n");
370 FreeList
= FreeList
->next
;
371 ((ppc_map_t
*)FreePage
)->addr
= MMU_ADDR_RESERVED
;
372 return ((ppc_map_t
*)FreePage
);
376 while(!mmuisfreepage(NextPage
) && NextPage
< PPC_PAGE_NUMBER(RamSize
))
380 if (NextPage
< PPC_PAGE_NUMBER(RamSize
))
384 fmtout("Problem! NextPage is low (%x)\n", NextPage
);
388 PpcPageTable
[NextPage
].addr
= MMU_ADDR_RESERVED
;
389 return &PpcPageTable
[NextPage
++];
398 void freepage(ppc_map_t
*PagePtr
)
400 MmuFreePage
*FreePage
= (MmuFreePage
*)PagePtr
;
401 PagePtr
->proc
= PagePtr
->addr
= 0;
402 FreePage
->next
= FreeList
;
406 MmuVsidTree
*allocvsidtree()
410 MmuVsidTree
*result
= (MmuVsidTree
*)FreeTree
;
411 FreeTree
= FreeTree
->next
;
414 else if(TreeAlloc
>= 3 || !NextTreePage
)
416 ppc_map_t
*map
= allocpage();
417 NextTreePage
= (MmuVsidTree
*)PPC_PAGE_ADDR((map
- PpcPageTable
));
423 return &NextTreePage
[TreeAlloc
++];
427 void freevsidtree(MmuVsidTree
*tree
)
430 for(i
= 0; i
< 256; i
++)
432 freepage(tree
->leaves
[i
]);
433 MmuFreeTree
*NextFreeTree
= (MmuFreeTree
*)tree
;
434 NextFreeTree
->next
= FreeTree
;
435 FreeTree
= NextFreeTree
;
438 void *allocvsid(int vsid
)
440 ppc_map_t
*map
= allocpage();
443 map
->pte
.pteh
= map
->pte
.ptel
= 0;
444 info
= (MmuVsidInfo
*)PPC_PAGE_ADDR((map
- PpcPageTable
));
446 info
->next
= VsidHead
;
451 void mmuallocvsid(int vsid
, int mask
)
454 for(i
= 0; i
< 16; i
++)
457 allocvsid((vsid
<< 4) + i
);
461 MmuVsidInfo
*findvsid(int vsid
)
464 for(info
= VsidHead
; info
; info
= info
->next
)
466 if(info
->vsid
== vsid
) return info
;
471 void freevsid(int vsid
)
474 MmuVsidInfo
*info
= findvsid(vsid
);
476 ppc_map_t
*map
= &PpcPageTable
[PPC_PAGE_NUMBER((paddr_t
)info
)];
477 for(i
= 0; i
< 256; i
++)
480 freevsidtree(info
->tree
[i
]);
485 void mmufreevsid(int vsid
, int mask
)
488 for(i
= 0; i
< 16; i
++)
491 freevsid((vsid
<< 4) + i
);
495 int mmuaddpage(ppc_map_info_t
*info
, int count
)
497 int i
, iva
= 0, vsid
, phys
, virt
;
499 int ptelo
, vsid_table_hi
, vsid_table_lo
;
501 MmuVsidInfo
*VsidInfo
;
502 MmuVsidTree
*VsidTree
;
504 for(i
= 0; i
< count
; i
++)
506 info
[i
].phys
&= ~PPC_PAGE_MASK
;
507 info
[i
].addr
&= ~PPC_PAGE_MASK
;
510 vsid
= ((info
[i
].addr
>> 28) & 15) | (info
[i
].proc
<< 4);
511 VsidInfo
= findvsid(vsid
);
513 if(!VsidInfo
) return -1;
515 ptehi
= (1 << 31) | (vsid
<< 7) | ((virt
>> 22) & 0x3f);
518 PagePtr
= &PpcPageTable
[PPC_PAGE_NUMBER(info
[i
].phys
)];
520 PagePtr
= allocpage();
527 phys
= PPC_PAGE_ADDR((PagePtr
- PpcPageTable
));
528 ptelo
= phys
& ~PPC_PAGE_MASK
;
532 /* Should not be allocating physical */
533 fmtout("Allocated physical: %x, logical %x\n", phys
, virt
);
534 fmtout("PagePtr %x (page %d)\n", PagePtr
, i
);
535 fmtout("info [ %x %x %x %x ]\n", info
[i
].proc
, info
[i
].addr
, info
[i
].flags
, info
[i
].phys
);
539 /* Update page data */
540 PagePtr
->pte
.pteh
= ptehi
;
541 PagePtr
->pte
.ptel
= ptelo
;
542 PagePtr
->proc
= info
[i
].proc
;
543 PagePtr
->addr
= virt
;
545 vsid_table_hi
= virt
>> 20 & 255;
546 vsid_table_lo
= virt
>> 12 & 255;
548 if(!VsidInfo
->tree
[vsid_table_hi
])
549 VsidInfo
->tree
[vsid_table_hi
] = allocvsidtree();
550 VsidTree
= VsidInfo
->tree
[vsid_table_hi
];
551 if(!VsidTree
) return 0;
552 VsidTree
->leaves
[vsid_table_lo
] = PagePtr
;
554 __asm__("tlbie %0\n\tsync\n\tisync" : : "r" (iva
));
561 ppc_map_t
*PagePtr
= allocpage();
562 if (!PagePtr
) return 0;
563 return PPC_PAGE_ADDR(PagePtr
- PpcPageTable
);
566 ppc_pteg_t
*PtegFromPage(ppc_map_t
*map
, int hfun
)
568 if(!map
->proc
&& !map
->addr
) return 0;
569 return &PpcHashedPTE
[PtegNumber(map
->addr
, hfun
)];
572 int PageMatch(vaddr_t addr
, ppc_pte_t pte
)
574 int vsid_pte
= (pte
.pteh
>> 7) & 15, api_pte
= pte
.pteh
& 63;
576 (((addr
>> 28) & 15) == vsid_pte
) &&
577 (((addr
>> 22) & 63) == api_pte
);
580 ppc_map_t
*mmuvirtmap(vaddr_t addr
)
582 int seg
= (addr
>> 28) & 15;
583 MmuVsidInfo
*seginfo
= Segs
[seg
];
584 MmuVsidTree
*segtree
= 0;
585 if(!seginfo
) return 0;
586 segtree
= seginfo
->tree
[(addr
>> 20) & 255];
587 if(!segtree
) return 0;
588 return segtree
->leaves
[(addr
>> 12) & 255];
591 void mmudelpage(ppc_map_info_t
*info
, int count
)
595 ppc_pteg_t
*PageEntry
;
596 ppc_pte_t ZeroPte
= { 0 };
598 for(i
= 0; i
< count
; i
++)
603 PagePtr
= &PpcPageTable
[ipa
];
604 info
[i
].proc
= PagePtr
->proc
;
605 info
[i
].addr
= PagePtr
->addr
;
609 PagePtr
= mmuvirtmap(info
[i
].addr
);
610 ipa
= PPC_PAGE_ADDR(PagePtr
- PpcPageTable
);
613 for(j
= 0; j
< 2; j
++)
615 PageEntry
= PtegFromPage(PagePtr
, j
);
616 for(k
= 0; k
< 8; k
++)
618 if(PageMatch(ipa
, PageEntry
->block
[k
]))
620 if(PageEntry
->block
[k
].ptel
& 0x100)
621 info
[i
].flags
|= MMU_PAGE_DIRTY
;
622 PageEntry
->block
[k
] = ZeroPte
;
627 __asm__("tlbie %0\n\tsync\n\tisync" : : "r" (info
[i
].addr
));
631 void mmugetpage(ppc_map_info_t
*info
, int count
)
636 for( i
= 0; i
< count
; i
++ )
638 if(!info
[i
].addr
&& !info
[i
].proc
)
640 PagePtr
= &((ppc_map_t
*)PAGETAB
)[info
[i
].phys
];
641 info
[i
].proc
= PagePtr
->proc
;
642 info
[i
].addr
= PagePtr
->addr
;
643 info
[i
].flags
= MMU_ALL_RW
;
645 vaddr_t addr
= info
[i
].addr
;
646 int vsid
= ((addr
>> 28) & 15) | (info
[i
].proc
<< 4);
647 PagePtr
= mmuvirtmap(info
[i
].addr
);
652 info
[i
].phys
= PPC_PAGE_ADDR(PagePtr
- PpcPageTable
);
653 info
[i
].flags
= MMU_ALL_RW
; // HACK
659 int mmuisfreepage(paddr_t pageno
)
661 ppc_map_t
*PagePtr
= PpcPageTable
+ pageno
;
662 return !PagePtr
->addr
;
665 void mmusetvsid(int start
, int end
, int vsid
)
668 for(i
= start
; i
< end
; i
++)
670 s_vsid
= (vsid
<< 4) | (i
& 15);
671 sr
= (GetSR(i
) & ~PPC_VSID_MASK
) | s_vsid
;
674 Segs
[i
] = findvsid(s_vsid
);
679 int ptegreload(ppc_trap_frame_t
*frame
, vaddr_t addr
)
681 int hfun
= (Clock
>> 3) & 1, ptegnum
= PtegNumber(addr
, hfun
);
682 ppc_map_t
*map
= mmuvirtmap(addr
);
684 map
->pte
.pteh
= (map
->pte
.pteh
& ~64) | (hfun
<< 6);
685 PpcHashedPTE
[ptegnum
].block
[Clock
& 7] = map
->pte
;
687 fmtout("Reloading addr %x (phys %x) at %x[%x] (%x:%x)\r\n",
688 addr
, PPC_PAGE_ADDR(map
- PpcPageTable
), ptegnum
, Clock
& 15,
689 PpcHashedPTE
[ptegnum
].block
[Clock
&7].pteh
,
690 PpcHashedPTE
[ptegnum
].block
[Clock
&7].ptel
);
693 __asm__("tlbie %0\n\tsync\n\tisync" : : "r" (addr
));
697 void printmap(vaddr_t vaddr
, ppc_map_t
*map
)
699 fmtout("%x: proc %x addr %x\n",
700 PPC_PAGE_ADDR(map
- PpcPageTable
),
704 void dumptree(vaddr_t vaddr
, MmuVsidTree
*tree
)
708 for (j
= 0; j
< 256; j
++)
712 printmap(vaddr
| (j
<< 12), tree
->leaves
[j
]);
717 void dumpvsid(MmuVsidInfo
*vsid
)
721 fmtout("vsid %d (%x):\n", vsid
->vsid
>>4, vsid
->vsid
<<28);
722 for (i
= 0; i
< 256; i
++)
726 dumptree((vsid
->vsid
<<28) | i
<< 20, vsid
->tree
[i
]);
736 fmtout("Address spaces:\n");
737 for (vsid
= VsidHead
; vsid
; vsid
= vsid
->next
)
743 void callkernel(void *fun_ptr
, void *arg
)
749 for (i
= 0; i
< 16; i
++)
751 // Patch up the vsid map. We shouldn't muck with these until we're
753 mmusetvsid(i
, i
+1, Vsid
[i
]);
756 void (*fun
)(void *) = fun_ptr
;
757 __asm__("mfmsr 3\n\t"
765 : : "r" (HTABORG
), "r" (arg
), "r" (fun
));