2 #include "ppcmmu/mmu.h"
3 #include "ppcmmu/mmuutil.h"
6 typedef unsigned long ULONG
;
12 0x00400 -- Instruction miss
13 0x10000 -- Entry point
15 0x20000 -- Physical map (PTE + Process Ptr + Address : 16 bytes)
17 4096 / 16 bytes = 256 entries per page
18 256 pages = 1Megabyte = 1 page table page
20 Setup by freeldr and used to build the kernel map, then used by the kernel
37 09 get first usable page
42 #define MMU_ADDR_RESERVED ((vaddr_t)-2)
44 MmuTrapHandler callback
[0x30];
45 typedef struct _MmuFreePage
{
47 struct _MmuFreePage
*next
;
49 typedef struct _MmuFreeTree
{
50 struct _MmuFreeTree
*next
;
52 typedef struct _MmuVsidTree
{
53 ppc_map_t
*leaves
[256];
55 typedef struct _MmuVsidInfo
{
57 struct _MmuVsidInfo
*next
;
58 MmuVsidTree
*tree
[256];
60 MmuFreePage
*FreeList
= 0;
61 // Pages are allocated one by one until NextPage == RamSize >> PPC_PAGE_SHIFT
62 // Then we take only from the free list
63 int Clock
= 0, TreeAlloc
= 0, GdbAttach
= 0, Booted
= 0, Vsid
[16];
64 paddr_t RamSize
, FirstUsablePage
, NextPage
;
65 MmuVsidTree
*NextTreePage
= 0;
66 MmuFreeTree
*FreeTree
;
67 MmuVsidInfo
*Segs
[16], *VsidHead
= 0;
69 extern void fmtout(const char *fmt
, ...);
71 int ptegreload(ppc_trap_frame_t
*frame
, vaddr_t addr
);
72 void SerialSetUp(int deviceType
, void *deviceAddr
, int baud
);
73 int SerialInterrupt(int n
, ppc_trap_frame_t
*tf
);
74 void TakeException(int n
, ppc_trap_frame_t
*tf
);
75 int mmuisfreepage(paddr_t pageno
);
76 void copy(void *t
, void *s
, int b
);
79 void trapcallback(int action
, ppc_trap_frame_t
*trap_frame
);
81 int _mmumain(int action
, void *arg1
, void *arg2
, void *arg3
, void *tf
)
83 ppc_trap_frame_t
*trap_frame
= (action
>= 0x100) ? tf
: arg1
;
90 if(!ptegreload(trap_frame
, trap_frame
->dar
))
92 trapcallback(action
, trap_frame
);
96 if(!ptegreload(trap_frame
, trap_frame
->srr0
))
98 trapcallback(action
, trap_frame
);
103 /* EE -- Try to get a serial interrupt if debugging enabled, then fall
104 * back to primary handler
106 if (!SerialInterrupt(action
, trap_frame
) && callback
[action
])
108 trapcallback(action
, trap_frame
);
120 trapcallback(action
, trap_frame
);
126 trap_frame
->srr1
|= 0x8000;
129 ret
= mmuaddpage(arg1
, (int)arg2
);
132 mmudelpage(arg1
, (int)arg2
);
135 mmusetvsid((int)arg1
, (int)arg2
, (int)arg3
);
138 ret
= (int)callback
[(int)arg1
];
139 callback
[(int)arg1
] = (MmuTrapHandler
)arg2
;
142 mmugetpage(arg1
, (int)arg2
);
148 callkernel(arg1
, arg2
);
151 mmusetramsize((paddr_t
)arg1
);
154 return FirstUsablePage
;
156 mmuallocvsid((int)arg1
, (int)arg2
);
159 mmufreevsid((int)arg1
, (int)arg2
);
165 copy(trap_frame
, (void *)0xf040, sizeof(*trap_frame
));
166 __asm__("mr 1,%0\n\tb trap_finish_start" : : "r"
167 (((int)trap_frame
) - 16));
174 SerialSetUp((int)arg1
, arg2
, 9600);
177 TakeException((int)arg1
, trap_frame
);
184 /* Restore bats when we were called voluntarily. We may not get a chance
185 * to do this after returning.
187 * At this point, we're in address space that matches physical space.
188 * We turn off mapping, restore bats, then let rfi switch us back to where
194 __asm__("mfmsr %0" : "=r" (tmp
));
196 __asm__("mtmsr %0" : : "r" (tmp
));
198 for(i
= 0; i
< 4; i
++) {
199 SetBat(i
, 0, GetPhys(0xf000 + i
* 16), GetPhys(0xf004 + i
* 16));
200 SetBat(i
, 1, GetPhys(0xf008 + i
* 16), GetPhys(0xf00c + i
* 16));
207 void trapcallback(int action
, ppc_trap_frame_t
*trap_frame
)
209 if ((paddr_t
)callback
[action
] < PAGETAB
)
210 callback
[action
](action
, trap_frame
);
213 int framecopy
= 0xf040;
214 copy((void *)framecopy
, trap_frame
, sizeof(*trap_frame
));
215 trap_frame
->srr0
= (int)callback
[action
];
216 trap_frame
->srr1
&= 0x7fff;
217 trap_frame
->gpr
[3] = action
;
218 trap_frame
->gpr
[4] = framecopy
;
219 __asm__("mr 1,%0\n\tsubi 1,1,16\n\tb trap_finish_start" : : "r" (trap_frame
));
225 SetPhysByte(0x800003f8, c
);
228 void copy(void *target
, void *src
, int bytes
)
230 while(bytes
--) *((char *)target
++) = *((char *)src
++);
233 void outstr(const char *str
)
235 while(*str
) outchar(*str
);
240 if(dig
< 10) outchar(dig
+ '0');
241 else outchar(dig
- 10 + 'A');
244 void outnum(unsigned long num
)
247 for( i
= 0; i
< 8; i
++ )
254 void fmtout(const char *str
, ...)
266 else if(str
[1] == 's')
268 outstr(va_arg(ap
, const char *));
272 outnum(va_arg(ap
, int));
285 void mmusetramsize(paddr_t ramsize
)
287 ppc_map_t
*last_map
= &PpcPageTable
[PPC_PAGE_NUMBER(ramsize
)];
291 FirstUsablePage
= (paddr_t
)last_map
;
292 NextPage
= PPC_PAGE_NUMBER(FirstUsablePage
) + 1;
296 int ignore(int trapCode
, ppc_trap_frame_t
*trap
)
301 int fpenable(int trapCode
, ppc_trap_frame_t
*trap
)
308 extern int trap_start
[], trap_end
[];
309 void copy_trap_handler(int trap
)
312 paddr_t targetArea
= trap
* 0x100;
314 /* Set target addr */
315 trap_end
[0] = (int)_mmumain
;
317 for (i
= 0; i
<= trap_end
- trap_start
; i
++)
319 SetPhys(targetArea
+ (i
* sizeof(int)), trap_start
[i
]);
327 for(i
= 0; i
< HTABSIZ
/ sizeof(int); i
++)
329 ((int *)HTABORG
)[i
] = 0;
332 /* Default to hang on unknown exception */
333 for(i
= 0; i
< 30; i
++)
335 callback
[i
] = (MmuTrapHandler
)TakeException
;
336 if (i
!= 1) /* Preserve reset handler */
337 copy_trap_handler(i
);
340 /* Serial Interrupt */
341 callback
[5] = 0; /* Do nothing until the user asks */
343 /* Program Exception */
344 callback
[6] = (MmuTrapHandler
)TakeException
;
346 /* Floating point exception */
347 callback
[8] = fpenable
;
349 /* Ignore decrementer and EE */
350 callback
[9] = ignore
;
353 callback
[0x20] = (MmuTrapHandler
)TakeException
;
356 ppc_map_t
*allocpage()
358 MmuFreePage
*FreePage
= 0;
362 if ((void *)FreeList
== (void *)PpcPageTable
)
364 fmtout("Problem! FreeList: page 0 is free\n");
369 FreeList
= FreeList
->next
;
370 ((ppc_map_t
*)FreePage
)->addr
= MMU_ADDR_RESERVED
;
371 return ((ppc_map_t
*)FreePage
);
375 while(!mmuisfreepage(NextPage
) && NextPage
< PPC_PAGE_NUMBER(RamSize
))
379 if (NextPage
< PPC_PAGE_NUMBER(RamSize
))
383 fmtout("Problem! NextPage is low (%x)\n", NextPage
);
387 PpcPageTable
[NextPage
].addr
= MMU_ADDR_RESERVED
;
388 return &PpcPageTable
[NextPage
++];
397 void freepage(ppc_map_t
*PagePtr
)
399 MmuFreePage
*FreePage
= (MmuFreePage
*)PagePtr
;
400 PagePtr
->proc
= PagePtr
->addr
= 0;
401 FreePage
->next
= FreeList
;
405 MmuVsidTree
*allocvsidtree()
409 MmuVsidTree
*result
= (MmuVsidTree
*)FreeTree
;
410 FreeTree
= FreeTree
->next
;
413 else if(TreeAlloc
>= 3 || !NextTreePage
)
415 ppc_map_t
*map
= allocpage();
416 NextTreePage
= (MmuVsidTree
*)PPC_PAGE_ADDR((map
- PpcPageTable
));
422 return &NextTreePage
[TreeAlloc
++];
426 void freevsidtree(MmuVsidTree
*tree
)
429 for(i
= 0; i
< 256; i
++)
431 freepage(tree
->leaves
[i
]);
432 MmuFreeTree
*NextFreeTree
= (MmuFreeTree
*)tree
;
433 NextFreeTree
->next
= FreeTree
;
434 FreeTree
= NextFreeTree
;
437 void *allocvsid(int vsid
)
439 ppc_map_t
*map
= allocpage();
442 map
->pte
.pteh
= map
->pte
.ptel
= 0;
443 info
= (MmuVsidInfo
*)PPC_PAGE_ADDR((map
- PpcPageTable
));
445 info
->next
= VsidHead
;
450 void mmuallocvsid(int vsid
, int mask
)
453 for(i
= 0; i
< 16; i
++)
456 allocvsid((vsid
<< 4) + i
);
460 MmuVsidInfo
*findvsid(int vsid
)
463 for(info
= VsidHead
; info
; info
= info
->next
)
465 if(info
->vsid
== vsid
) return info
;
470 void freevsid(int vsid
)
473 MmuVsidInfo
*info
= findvsid(vsid
);
475 ppc_map_t
*map
= &PpcPageTable
[PPC_PAGE_NUMBER((paddr_t
)info
)];
476 for(i
= 0; i
< 256; i
++)
479 freevsidtree(info
->tree
[i
]);
484 void mmufreevsid(int vsid
, int mask
)
487 for(i
= 0; i
< 16; i
++)
490 freevsid((vsid
<< 4) + i
);
494 int mmuaddpage(ppc_map_info_t
*info
, int count
)
496 int i
, iva
= 0, vsid
, phys
, virt
;
498 int ptelo
, vsid_table_hi
, vsid_table_lo
;
500 MmuVsidInfo
*VsidInfo
;
501 MmuVsidTree
*VsidTree
;
503 for(i
= 0; i
< count
; i
++)
505 info
[i
].phys
&= ~PPC_PAGE_MASK
;
506 info
[i
].addr
&= ~PPC_PAGE_MASK
;
509 vsid
= ((info
[i
].addr
>> 28) & 15) | (info
[i
].proc
<< 4);
510 VsidInfo
= findvsid(vsid
);
512 if(!VsidInfo
) return -1;
514 ptehi
= (1 << 31) | (vsid
<< 7) | ((virt
>> 22) & 0x3f);
517 PagePtr
= &PpcPageTable
[PPC_PAGE_NUMBER(info
[i
].phys
)];
519 PagePtr
= allocpage();
526 phys
= PPC_PAGE_ADDR((PagePtr
- PpcPageTable
));
527 ptelo
= phys
& ~PPC_PAGE_MASK
;
531 /* Should not be allocating physical */
532 fmtout("Allocated physical: %x, logical %x\n", phys
, virt
);
533 fmtout("PagePtr %x (page %d)\n", PagePtr
, i
);
534 fmtout("info [ %x %x %x %x ]\n", info
[i
].proc
, info
[i
].addr
, info
[i
].flags
, info
[i
].phys
);
538 /* Update page data */
539 PagePtr
->pte
.pteh
= ptehi
;
540 PagePtr
->pte
.ptel
= ptelo
;
541 PagePtr
->proc
= info
[i
].proc
;
542 PagePtr
->addr
= virt
;
544 vsid_table_hi
= virt
>> 20 & 255;
545 vsid_table_lo
= virt
>> 12 & 255;
547 if(!VsidInfo
->tree
[vsid_table_hi
])
548 VsidInfo
->tree
[vsid_table_hi
] = allocvsidtree();
549 VsidTree
= VsidInfo
->tree
[vsid_table_hi
];
550 if(!VsidTree
) return 0;
551 VsidTree
->leaves
[vsid_table_lo
] = PagePtr
;
553 __asm__("tlbie %0\n\tsync\n\tisync" : : "r" (iva
));
560 ppc_map_t
*PagePtr
= allocpage();
561 if (!PagePtr
) return 0;
562 return PPC_PAGE_ADDR(PagePtr
- PpcPageTable
);
565 ppc_pteg_t
*PtegFromPage(ppc_map_t
*map
, int hfun
)
567 if(!map
->proc
&& !map
->addr
) return 0;
568 return &PpcHashedPTE
[PtegNumber(map
->addr
, hfun
)];
571 int PageMatch(vaddr_t addr
, ppc_pte_t pte
)
573 int vsid_pte
= (pte
.pteh
>> 7) & 15, api_pte
= pte
.pteh
& 63;
575 (((addr
>> 28) & 15) == vsid_pte
) &&
576 (((addr
>> 22) & 63) == api_pte
);
579 ppc_map_t
*mmuvirtmap(vaddr_t addr
)
581 int seg
= (addr
>> 28) & 15;
582 MmuVsidInfo
*seginfo
= Segs
[seg
];
583 MmuVsidTree
*segtree
= 0;
584 if(!seginfo
) return 0;
585 segtree
= seginfo
->tree
[(addr
>> 20) & 255];
586 if(!segtree
) return 0;
587 return segtree
->leaves
[(addr
>> 12) & 255];
590 void mmudelpage(ppc_map_info_t
*info
, int count
)
594 ppc_pteg_t
*PageEntry
;
595 ppc_pte_t ZeroPte
= { 0 };
597 for(i
= 0; i
< count
; i
++)
602 PagePtr
= &PpcPageTable
[ipa
];
603 info
[i
].proc
= PagePtr
->proc
;
604 info
[i
].addr
= PagePtr
->addr
;
608 PagePtr
= mmuvirtmap(info
[i
].addr
);
609 ipa
= PPC_PAGE_ADDR(PagePtr
- PpcPageTable
);
612 for(j
= 0; j
< 2; j
++)
614 PageEntry
= PtegFromPage(PagePtr
, j
);
615 for(k
= 0; k
< 8; k
++)
617 if(PageMatch(ipa
, PageEntry
->block
[k
]))
619 if(PageEntry
->block
[k
].ptel
& 0x100)
620 info
[i
].flags
|= MMU_PAGE_DIRTY
;
621 PageEntry
->block
[k
] = ZeroPte
;
626 __asm__("tlbie %0\n\tsync\n\tisync" : : "r" (info
[i
].addr
));
630 void mmugetpage(ppc_map_info_t
*info
, int count
)
635 for( i
= 0; i
< count
; i
++ )
637 if(!info
[i
].addr
&& !info
[i
].proc
)
639 PagePtr
= &((ppc_map_t
*)PAGETAB
)[info
[i
].phys
];
640 info
[i
].proc
= PagePtr
->proc
;
641 info
[i
].addr
= PagePtr
->addr
;
642 info
[i
].flags
= MMU_ALL_RW
;
644 vaddr_t addr
= info
[i
].addr
;
645 int vsid
= ((addr
>> 28) & 15) | (info
[i
].proc
<< 4);
646 PagePtr
= mmuvirtmap(info
[i
].addr
);
651 info
[i
].phys
= PPC_PAGE_ADDR(PagePtr
- PpcPageTable
);
652 info
[i
].flags
= MMU_ALL_RW
; // HACK
658 int mmuisfreepage(paddr_t pageno
)
660 ppc_map_t
*PagePtr
= PpcPageTable
+ pageno
;
661 return !PagePtr
->addr
;
664 void mmusetvsid(int start
, int end
, int vsid
)
667 for(i
= start
; i
< end
; i
++)
669 s_vsid
= (vsid
<< 4) | (i
& 15);
670 sr
= (GetSR(i
) & ~PPC_VSID_MASK
) | s_vsid
;
673 Segs
[i
] = findvsid(s_vsid
);
678 int ptegreload(ppc_trap_frame_t
*frame
, vaddr_t addr
)
680 int hfun
= (Clock
>> 3) & 1, ptegnum
= PtegNumber(addr
, hfun
);
681 ppc_map_t
*map
= mmuvirtmap(addr
);
683 map
->pte
.pteh
= (map
->pte
.pteh
& ~64) | (hfun
<< 6);
684 PpcHashedPTE
[ptegnum
].block
[Clock
& 7] = map
->pte
;
686 fmtout("Reloading addr %x (phys %x) at %x[%x] (%x:%x)\r\n",
687 addr
, PPC_PAGE_ADDR(map
- PpcPageTable
), ptegnum
, Clock
& 15,
688 PpcHashedPTE
[ptegnum
].block
[Clock
&7].pteh
,
689 PpcHashedPTE
[ptegnum
].block
[Clock
&7].ptel
);
692 __asm__("tlbie %0\n\tsync\n\tisync" : : "r" (addr
));
696 void printmap(vaddr_t vaddr
, ppc_map_t
*map
)
698 fmtout("%x: proc %x addr %x\n",
699 PPC_PAGE_ADDR(map
- PpcPageTable
),
703 void dumptree(vaddr_t vaddr
, MmuVsidTree
*tree
)
707 for (j
= 0; j
< 256; j
++)
711 printmap(vaddr
| (j
<< 12), tree
->leaves
[j
]);
716 void dumpvsid(MmuVsidInfo
*vsid
)
720 fmtout("vsid %d (%x):\n", vsid
->vsid
>>4, vsid
->vsid
<<28);
721 for (i
= 0; i
< 256; i
++)
725 dumptree((vsid
->vsid
<<28) | i
<< 20, vsid
->tree
[i
]);
735 fmtout("Address spaces:\n");
736 for (vsid
= VsidHead
; vsid
; vsid
= vsid
->next
)
742 void callkernel(void *fun_ptr
, void *arg
)
748 for (i
= 0; i
< 16; i
++)
750 // Patch up the vsid map. We shouldn't muck with these until we're
752 mmusetvsid(i
, i
+1, Vsid
[i
]);
755 void (*fun
)(void *) = fun_ptr
;
756 __asm__("mfmsr 3\n\t"
764 : : "r" (HTABORG
), "r" (arg
), "r" (fun
));