mirror of
https://github.com/reactos/reactos.git
synced 2024-08-26 13:18:51 +00:00
767 lines
16 KiB
C
767 lines
16 KiB
C
#include <stdarg.h>
|
|
#include "ppcmmu/mmu.h"
|
|
#include "ppcmmu/mmuutil.h"
|
|
#include "mmuobject.h"
|
|
|
|
typedef unsigned long ULONG;
|
|
|
|
/*
|
|
|
|
The MMU Object:
|
|
0x00300 -- Data miss
|
|
0x00400 -- Instruction miss
|
|
0x10000 -- Entry point
|
|
... Code
|
|
0x20000 -- Physical map (PTE + Process Ptr + Address : 16 bytes)
|
|
|
|
4096 / 16 bytes = 256 entries per page
|
|
256 pages = 1Megabyte = 1 page table page
|
|
|
|
Setup by freeldr and used to build the kernel map, then used by the kernel
|
|
|
|
Calling:
|
|
|
|
r3 -- Action
|
|
r4 .. r6 -- Args
|
|
|
|
Actions:
|
|
00 Init
|
|
01 Map pages
|
|
02 erase pages
|
|
03 set segment vsid
|
|
04 page miss callback
|
|
05 inquire page
|
|
06 unit test
|
|
07 alloc page
|
|
08 set memory size
|
|
09 get first usable page
|
|
10 alloc vsid
|
|
11 revoke vsid
|
|
*/
|
|
|
|
#define MMU_ADDR_RESERVED ((vaddr_t)-2)
|
|
|
|
MmuTrapHandler callback[0x30];
|
|
typedef struct _MmuFreePage {
|
|
int page;
|
|
struct _MmuFreePage *next;
|
|
} MmuFreePage;
|
|
typedef struct _MmuFreeTree {
|
|
struct _MmuFreeTree *next;
|
|
} MmuFreeTree;
|
|
typedef struct _MmuVsidTree {
|
|
ppc_map_t *leaves[256];
|
|
} MmuVsidTree;
|
|
typedef struct _MmuVsidInfo {
|
|
int vsid;
|
|
struct _MmuVsidInfo *next;
|
|
MmuVsidTree *tree[256];
|
|
} MmuVsidInfo;
|
|
MmuFreePage *FreeList = 0;
|
|
// Pages are allocated one by one until NextPage == RamSize >> PPC_PAGE_SHIFT
|
|
// Then we take only from the free list
|
|
int Clock = 0, TreeAlloc = 0, GdbAttach = 0, Booted = 0, Vsid[16];
|
|
paddr_t RamSize, FirstUsablePage, NextPage;
|
|
MmuVsidTree *NextTreePage = 0;
|
|
MmuFreeTree *FreeTree;
|
|
MmuVsidInfo *Segs[16], *VsidHead = 0;
|
|
|
|
extern void fmtout(const char *fmt, ...);
|
|
extern char *serport;
|
|
int ptegreload(ppc_trap_frame_t *frame, vaddr_t addr);
|
|
void SerialSetUp(int deviceType, void *deviceAddr, int baud);
|
|
int SerialInterrupt(int n, ppc_trap_frame_t *tf);
|
|
void TakeException(int n, ppc_trap_frame_t *tf);
|
|
int mmuisfreepage(paddr_t pageno);
|
|
void copy(void *t, void *s, int b);
|
|
paddr_t mmunewpage();
|
|
void dumpmap();
|
|
void trapcallback(int action, ppc_trap_frame_t *trap_frame);
|
|
|
|
int _mmumain(int action, void *arg1, void *arg2, void *arg3, void *tf)
|
|
{
|
|
ppc_trap_frame_t *trap_frame = (action >= 0x100) ? tf : arg1;
|
|
int ret = 0, tmp, i;
|
|
|
|
switch(action)
|
|
{
|
|
/* Trap Handlers */
|
|
case 3:
|
|
if(!ptegreload(trap_frame, trap_frame->dar))
|
|
{
|
|
trapcallback(action, trap_frame);
|
|
}
|
|
break;
|
|
case 4:
|
|
if(!ptegreload(trap_frame, trap_frame->srr0))
|
|
{
|
|
trapcallback(action, trap_frame);
|
|
}
|
|
break;
|
|
|
|
case 5:
|
|
/* EE -- Try to get a serial interrupt if debugging enabled, then fall
|
|
* back to primary handler
|
|
*/
|
|
if (!SerialInterrupt(action, trap_frame) && callback[action])
|
|
{
|
|
trapcallback(action, trap_frame);
|
|
}
|
|
break;
|
|
case 0:
|
|
case 2:
|
|
case 6:
|
|
case 7:
|
|
case 8:
|
|
case 9:
|
|
case 0xa:
|
|
case 0xc:
|
|
case 0x20:
|
|
trapcallback(action, trap_frame);
|
|
break;
|
|
|
|
/* MMU Functions */
|
|
case 0x100:
|
|
initme();
|
|
trap_frame->srr1 |= 0x8000;
|
|
break;
|
|
case 0x101:
|
|
ret = mmuaddpage(arg1, (int)arg2);
|
|
break;
|
|
case 0x102:
|
|
mmudelpage(arg1, (int)arg2);
|
|
break;
|
|
case 0x103:
|
|
mmusetvsid((int)arg1, (int)arg2, (int)arg3);
|
|
break;
|
|
case 0x104:
|
|
ret = (int)callback[(int)arg1];
|
|
callback[(int)arg1] = (MmuTrapHandler)arg2;
|
|
break;
|
|
case 0x105:
|
|
mmugetpage(arg1, (int)arg2);
|
|
break;
|
|
case 0x106:
|
|
ret = mmunitest();
|
|
break;
|
|
case 0x107:
|
|
callkernel(arg1, arg2);
|
|
break;
|
|
case 0x108:
|
|
mmusetramsize((paddr_t)arg1);
|
|
break;
|
|
case 0x109:
|
|
return FirstUsablePage;
|
|
case 0x10a:
|
|
mmuallocvsid((int)arg1, (int)arg2);
|
|
break;
|
|
case 0x10b:
|
|
mmufreevsid((int)arg1, (int)arg2);
|
|
break;
|
|
case 0x10c:
|
|
ret = mmunewpage();
|
|
break;
|
|
case 0x10d:
|
|
copy(trap_frame, (void *)0xf040, sizeof(*trap_frame));
|
|
__asm__("mr 1,%0\n\tb trap_finish_start" : : "r"
|
|
(((int)trap_frame) - 16));
|
|
break;
|
|
case 0x10e:
|
|
dumpmap();
|
|
break;
|
|
|
|
case 0x200:
|
|
SerialSetUp((int)arg1, arg2, 9600);
|
|
break;
|
|
case 0x201:
|
|
TakeException((int)arg1, trap_frame);
|
|
break;
|
|
|
|
default:
|
|
while(1);
|
|
}
|
|
|
|
/* Restore bats when we were called voluntarily. We may not get a chance
|
|
* to do this after returning.
|
|
*
|
|
* At this point, we're in address space that matches physical space.
|
|
* We turn off mapping, restore bats, then let rfi switch us back to where
|
|
* we came.
|
|
*/
|
|
|
|
if (action >= 0x100)
|
|
{
|
|
__asm__("mfmsr %0" : "=r" (tmp));
|
|
tmp &= ~0x30;
|
|
__asm__("mtmsr %0" : : "r" (tmp));
|
|
|
|
for(i = 0; i < 4; i++) {
|
|
SetBat(i, 0, GetPhys(0xf000 + i * 16), GetPhys(0xf004 + i * 16));
|
|
SetBat(i, 1, GetPhys(0xf008 + i * 16), GetPhys(0xf00c + i * 16));
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void trapcallback(int action, ppc_trap_frame_t *trap_frame)
|
|
{
|
|
if ((paddr_t)callback[action] < PAGETAB)
|
|
callback[action](action, trap_frame);
|
|
else
|
|
{
|
|
int framecopy = 0xf040;
|
|
copy((void *)framecopy, trap_frame, sizeof(*trap_frame));
|
|
trap_frame->srr0 = (int)callback[action];
|
|
trap_frame->srr1 &= 0x7fff;
|
|
trap_frame->gpr[3] = action;
|
|
trap_frame->gpr[4] = framecopy;
|
|
__asm__("mr 1,%0\n\tsubi 1,1,16\n\tb trap_finish_start" : : "r" (trap_frame));
|
|
}
|
|
}
|
|
|
|
void outchar(char c)
|
|
{
|
|
SetPhysByte(0x800003f8, c);
|
|
}
|
|
|
|
void copy(void *target, void *src, int bytes)
|
|
{
|
|
while(bytes--) *((char *)target++) = *((char *)src++);
|
|
}
|
|
|
|
void outstr(const char *str)
|
|
{
|
|
while(*str) outchar(*str);
|
|
}
|
|
|
|
void outdig(int dig)
|
|
{
|
|
if(dig < 10) outchar(dig + '0');
|
|
else outchar(dig - 10 + 'A');
|
|
}
|
|
|
|
void outnum(unsigned long num)
|
|
{
|
|
int i;
|
|
for( i = 0; i < 8; i++ )
|
|
{
|
|
outdig(num >> 28);
|
|
num <<= 4;
|
|
}
|
|
}
|
|
|
|
void fmtout(const char *str, ...)
|
|
{
|
|
va_list ap;
|
|
va_start(ap, str);
|
|
while(*str)
|
|
{
|
|
if(*str == '%')
|
|
{
|
|
if(str[1] == '%')
|
|
{
|
|
outchar('%');
|
|
}
|
|
else if(str[1] == 's')
|
|
{
|
|
outstr(va_arg(ap, const char *));
|
|
}
|
|
else
|
|
{
|
|
outnum(va_arg(ap, int));
|
|
}
|
|
str++;
|
|
}
|
|
else
|
|
{
|
|
outchar(*str);
|
|
}
|
|
str++;
|
|
}
|
|
va_end(ap);
|
|
}
|
|
|
|
void mmusetramsize(paddr_t ramsize)
|
|
{
|
|
ppc_map_t *last_map = &PpcPageTable[PPC_PAGE_NUMBER(ramsize)];
|
|
if(!RamSize)
|
|
{
|
|
RamSize = ramsize;
|
|
FirstUsablePage = (paddr_t)last_map;
|
|
NextPage = PPC_PAGE_NUMBER(FirstUsablePage) + 1;
|
|
}
|
|
}
|
|
|
|
int ignore(int trapCode, ppc_trap_frame_t *trap)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
int fpenable(int trapCode, ppc_trap_frame_t *trap)
|
|
{
|
|
/* Turn on FP */
|
|
trap->srr1 |= 8192;
|
|
return 1;
|
|
}
|
|
|
|
extern int trap_start[], trap_end[];
|
|
void copy_trap_handler(int trap)
|
|
{
|
|
int i;
|
|
paddr_t targetArea = trap * 0x100;
|
|
|
|
/* Set target addr */
|
|
trap_end[0] = (int)_mmumain;
|
|
|
|
for (i = 0; i <= trap_end - trap_start; i++)
|
|
{
|
|
SetPhys(targetArea + (i * sizeof(int)), trap_start[i]);
|
|
}
|
|
}
|
|
|
|
void initme()
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < HTABSIZ / sizeof(int); i++)
|
|
{
|
|
((int *)HTABORG)[i] = 0;
|
|
}
|
|
|
|
/* Default to hang on unknown exception */
|
|
for(i = 0; i < 30; i++)
|
|
{
|
|
callback[i] = (MmuTrapHandler)TakeException;
|
|
if (i != 1) /* Preserve reset handler */
|
|
copy_trap_handler(i);
|
|
}
|
|
|
|
/* Serial Interrupt */
|
|
callback[5] = 0; /* Do nothing until the user asks */
|
|
|
|
/* Program Exception */
|
|
callback[6] = (MmuTrapHandler)TakeException;
|
|
|
|
/* Floating point exception */
|
|
callback[8] = fpenable;
|
|
|
|
/* Ignore decrementer and EE */
|
|
callback[9] = ignore;
|
|
|
|
/* Single Step */
|
|
callback[0x20] = (MmuTrapHandler)TakeException;
|
|
}
|
|
|
|
ppc_map_t *allocpage()
|
|
{
|
|
MmuFreePage *FreePage = 0;
|
|
|
|
if (FreeList)
|
|
{
|
|
if ((void *)FreeList == (void *)PpcPageTable)
|
|
{
|
|
fmtout("Problem! FreeList: page 0 is free\n");
|
|
while(1);
|
|
}
|
|
|
|
FreePage = FreeList;
|
|
FreeList = FreeList->next;
|
|
((ppc_map_t*)FreePage)->addr = MMU_ADDR_RESERVED;
|
|
return ((ppc_map_t*)FreePage);
|
|
}
|
|
else
|
|
{
|
|
while(!mmuisfreepage(NextPage) && NextPage < PPC_PAGE_NUMBER(RamSize))
|
|
{
|
|
NextPage++;
|
|
}
|
|
if (NextPage < PPC_PAGE_NUMBER(RamSize))
|
|
{
|
|
if (NextPage < 0x30)
|
|
{
|
|
fmtout("Problem! NextPage is low (%x)\n", NextPage);
|
|
while(1);
|
|
}
|
|
|
|
PpcPageTable[NextPage].addr = MMU_ADDR_RESERVED;
|
|
return &PpcPageTable[NextPage++];
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
void freepage(ppc_map_t *PagePtr)
|
|
{
|
|
MmuFreePage *FreePage = (MmuFreePage*)PagePtr;
|
|
PagePtr->proc = PagePtr->addr = 0;
|
|
FreePage->next = FreeList;
|
|
FreeList = FreePage;
|
|
}
|
|
|
|
MmuVsidTree *allocvsidtree()
|
|
{
|
|
if(FreeTree)
|
|
{
|
|
MmuVsidTree *result = (MmuVsidTree*)FreeTree;
|
|
FreeTree = FreeTree->next;
|
|
return result;
|
|
}
|
|
else if(TreeAlloc >= 3 || !NextTreePage)
|
|
{
|
|
ppc_map_t *map = allocpage();
|
|
NextTreePage = (MmuVsidTree*)PPC_PAGE_ADDR((map - PpcPageTable));
|
|
TreeAlloc = 1;
|
|
return NextTreePage;
|
|
}
|
|
else
|
|
{
|
|
return &NextTreePage[TreeAlloc++];
|
|
}
|
|
}
|
|
|
|
void freevsidtree(MmuVsidTree *tree)
|
|
{
|
|
int i;
|
|
for(i = 0; i < 256; i++)
|
|
if(tree->leaves[i])
|
|
freepage(tree->leaves[i]);
|
|
MmuFreeTree *NextFreeTree = (MmuFreeTree *)tree;
|
|
NextFreeTree->next = FreeTree;
|
|
FreeTree = NextFreeTree;
|
|
}
|
|
|
|
void *allocvsid(int vsid)
|
|
{
|
|
ppc_map_t *map = allocpage();
|
|
MmuVsidInfo *info;
|
|
if(!map) return 0;
|
|
map->pte.pteh = map->pte.ptel = 0;
|
|
info = (MmuVsidInfo*)PPC_PAGE_ADDR((map - PpcPageTable));
|
|
info->vsid = vsid;
|
|
info->next = VsidHead;
|
|
VsidHead = info;
|
|
return info;
|
|
}
|
|
|
|
void mmuallocvsid(int vsid, int mask)
|
|
{
|
|
int i;
|
|
for(i = 0; i < 16; i++)
|
|
{
|
|
if(mask & (1 << i))
|
|
allocvsid((vsid << 4) + i);
|
|
}
|
|
}
|
|
|
|
MmuVsidInfo *findvsid(int vsid)
|
|
{
|
|
MmuVsidInfo *info;
|
|
for(info = VsidHead; info; info = info->next)
|
|
{
|
|
if(info->vsid == vsid) return info;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void freevsid(int vsid)
|
|
{
|
|
int i;
|
|
MmuVsidInfo *info = findvsid(vsid);
|
|
if(!info) return;
|
|
ppc_map_t *map = &PpcPageTable[PPC_PAGE_NUMBER((paddr_t)info)];
|
|
for(i = 0; i < 256; i++)
|
|
{
|
|
if(info->tree[i])
|
|
freevsidtree(info->tree[i]);
|
|
}
|
|
freepage(map);
|
|
}
|
|
|
|
void mmufreevsid(int vsid, int mask)
|
|
{
|
|
int i;
|
|
for(i = 0; i < 16; i++)
|
|
{
|
|
if(mask & (1 << i))
|
|
freevsid((vsid << 4) + i);
|
|
}
|
|
}
|
|
|
|
int mmuaddpage(ppc_map_info_t *info, int count)
|
|
{
|
|
int i, iva = 0, vsid, phys, virt;
|
|
int ptehi;
|
|
int ptelo, vsid_table_hi, vsid_table_lo;
|
|
ppc_map_t *PagePtr;
|
|
MmuVsidInfo *VsidInfo;
|
|
MmuVsidTree *VsidTree;
|
|
|
|
for(i = 0; i < count; i++)
|
|
{
|
|
info[i].phys &= ~PPC_PAGE_MASK;
|
|
info[i].addr &= ~PPC_PAGE_MASK;
|
|
|
|
virt = info[i].addr;
|
|
vsid = ((info[i].addr >> 28) & 15) | (info[i].proc << 4);
|
|
VsidInfo = findvsid(vsid);
|
|
|
|
if(!VsidInfo) return -1;
|
|
|
|
ptehi = (1 << 31) | (vsid << 7) | ((virt >> 22) & 0x3f);
|
|
|
|
if(info[i].phys) {
|
|
PagePtr = &PpcPageTable[PPC_PAGE_NUMBER(info[i].phys)];
|
|
} else {
|
|
PagePtr = allocpage();
|
|
if(!PagePtr)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
phys = PPC_PAGE_ADDR((PagePtr - PpcPageTable));
|
|
ptelo = phys & ~PPC_PAGE_MASK;
|
|
|
|
if (phys < 0x30000)
|
|
{
|
|
/* Should not be allocating physical */
|
|
fmtout("Allocated physical: %x, logical %x\n", phys, virt);
|
|
fmtout("PagePtr %x (page %d)\n", PagePtr, i);
|
|
fmtout("info [ %x %x %x %x ]\n", info[i].proc, info[i].addr, info[i].flags, info[i].phys);
|
|
while(1);
|
|
}
|
|
|
|
/* Update page data */
|
|
PagePtr->pte.pteh = ptehi;
|
|
PagePtr->pte.ptel = ptelo;
|
|
PagePtr->proc = info[i].proc;
|
|
PagePtr->addr = virt;
|
|
|
|
vsid_table_hi = virt >> 20 & 255;
|
|
vsid_table_lo = virt >> 12 & 255;
|
|
|
|
if(!VsidInfo->tree[vsid_table_hi])
|
|
VsidInfo->tree[vsid_table_hi] = allocvsidtree();
|
|
VsidTree = VsidInfo->tree[vsid_table_hi];
|
|
if(!VsidTree) return 0;
|
|
VsidTree->leaves[vsid_table_lo] = PagePtr;
|
|
|
|
__asm__("tlbie %0\n\tsync\n\tisync" : : "r" (iva));
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
paddr_t mmunewpage()
|
|
{
|
|
ppc_map_t *PagePtr = allocpage();
|
|
if (!PagePtr) return 0;
|
|
return PPC_PAGE_ADDR(PagePtr - PpcPageTable);
|
|
}
|
|
|
|
ppc_pteg_t *PtegFromPage(ppc_map_t *map, int hfun)
|
|
{
|
|
if(!map->proc && !map->addr) return 0;
|
|
return &PpcHashedPTE[PtegNumber(map->addr, hfun)];
|
|
}
|
|
|
|
int PageMatch(vaddr_t addr, ppc_pte_t pte)
|
|
{
|
|
int vsid_pte = (pte.pteh >> 7) & 15, api_pte = pte.pteh & 63;
|
|
return
|
|
(((addr >> 28) & 15) == vsid_pte) &&
|
|
(((addr >> 22) & 63) == api_pte);
|
|
}
|
|
|
|
ppc_map_t *mmuvirtmap(vaddr_t addr)
|
|
{
|
|
int seg = (addr >> 28) & 15;
|
|
MmuVsidInfo *seginfo = Segs[seg];
|
|
MmuVsidTree *segtree = 0;
|
|
if(!seginfo) return 0;
|
|
segtree = seginfo->tree[(addr >> 20) & 255];
|
|
if(!segtree) return 0;
|
|
return segtree->leaves[(addr >> 12) & 255];
|
|
}
|
|
|
|
void mmudelpage(ppc_map_info_t *info, int count)
|
|
{
|
|
int i, j, k, ipa;
|
|
ppc_map_t *PagePtr;
|
|
ppc_pteg_t *PageEntry;
|
|
ppc_pte_t ZeroPte = { 0 };
|
|
|
|
for(i = 0; i < count; i++)
|
|
{
|
|
if (info[i].phys)
|
|
{
|
|
ipa = info[i].phys;
|
|
PagePtr = &PpcPageTable[ipa];
|
|
info[i].proc = PagePtr->proc;
|
|
info[i].addr = PagePtr->addr;
|
|
}
|
|
else
|
|
{
|
|
PagePtr = mmuvirtmap(info[i].addr);
|
|
ipa = PPC_PAGE_ADDR(PagePtr - PpcPageTable);
|
|
}
|
|
|
|
for(j = 0; j < 2; j++)
|
|
{
|
|
PageEntry = PtegFromPage(PagePtr, j);
|
|
for(k = 0; k < 8; k++)
|
|
{
|
|
if(PageMatch(ipa, PageEntry->block[k]))
|
|
{
|
|
if(PageEntry->block[k].ptel & 0x100)
|
|
info[i].flags |= MMU_PAGE_DIRTY;
|
|
PageEntry->block[k] = ZeroPte;
|
|
}
|
|
}
|
|
}
|
|
freepage(PagePtr);
|
|
__asm__("tlbie %0\n\tsync\n\tisync" : : "r" (info[i].addr));
|
|
}
|
|
}
|
|
|
|
void mmugetpage(ppc_map_info_t *info, int count)
|
|
{
|
|
int i;
|
|
ppc_map_t *PagePtr;
|
|
|
|
for( i = 0; i < count; i++ )
|
|
{
|
|
if(!info[i].addr && !info[i].proc)
|
|
{
|
|
PagePtr = &((ppc_map_t*)PAGETAB)[info[i].phys];
|
|
info[i].proc = PagePtr->proc;
|
|
info[i].addr = PagePtr->addr;
|
|
info[i].flags = MMU_ALL_RW;
|
|
} else {
|
|
vaddr_t addr = info[i].addr;
|
|
int vsid = ((addr >> 28) & 15) | (info[i].proc << 4);
|
|
PagePtr = mmuvirtmap(info[i].addr);
|
|
if(!PagePtr)
|
|
info[i].phys = 0;
|
|
else
|
|
{
|
|
info[i].phys = PPC_PAGE_ADDR(PagePtr - PpcPageTable);
|
|
info[i].flags = MMU_ALL_RW; // HACK
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int mmuisfreepage(paddr_t pageno)
|
|
{
|
|
ppc_map_t *PagePtr = PpcPageTable + pageno;
|
|
return !PagePtr->addr;
|
|
}
|
|
|
|
void mmusetvsid(int start, int end, int vsid)
|
|
{
|
|
int i, sr, s_vsid;
|
|
for(i = start; i < end; i++)
|
|
{
|
|
s_vsid = (vsid << 4) | (i & 15);
|
|
sr = (GetSR(i) & ~PPC_VSID_MASK) | s_vsid;
|
|
if (Booted)
|
|
SetSR(i, sr);
|
|
Segs[i] = findvsid(s_vsid);
|
|
Vsid[i] = vsid;
|
|
}
|
|
}
|
|
|
|
int ptegreload(ppc_trap_frame_t *frame, vaddr_t addr)
|
|
{
|
|
int hfun = (Clock >> 3) & 1, ptegnum = PtegNumber(addr, hfun);
|
|
ppc_map_t *map = mmuvirtmap(addr);
|
|
if(!map) return 0;
|
|
map->pte.pteh = (map->pte.pteh & ~64) | (hfun << 6);
|
|
PpcHashedPTE[ptegnum].block[Clock & 7] = map->pte;
|
|
#if 0
|
|
fmtout("Reloading addr %x (phys %x) at %x[%x] (%x:%x)\r\n",
|
|
addr, PPC_PAGE_ADDR(map - PpcPageTable), ptegnum, Clock & 15,
|
|
PpcHashedPTE[ptegnum].block[Clock&7].pteh,
|
|
PpcHashedPTE[ptegnum].block[Clock&7].ptel);
|
|
#endif
|
|
Clock++;
|
|
__asm__("tlbie %0\n\tsync\n\tisync" : : "r" (addr));
|
|
return 1;
|
|
}
|
|
|
|
void printmap(vaddr_t vaddr, ppc_map_t *map)
|
|
{
|
|
fmtout("%x: proc %x addr %x\n",
|
|
PPC_PAGE_ADDR(map - PpcPageTable),
|
|
map->proc, vaddr);
|
|
}
|
|
|
|
void dumptree(vaddr_t vaddr, MmuVsidTree *tree)
|
|
{
|
|
int j;
|
|
|
|
for (j = 0; j < 256; j++)
|
|
{
|
|
if (tree->leaves[j])
|
|
{
|
|
printmap(vaddr | (j << 12), tree->leaves[j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void dumpvsid(MmuVsidInfo *vsid)
|
|
{
|
|
int i;
|
|
|
|
fmtout("vsid %d (%x):\n", vsid->vsid>>4, vsid->vsid<<28);
|
|
for (i = 0; i < 256; i++)
|
|
{
|
|
if (vsid->tree[i])
|
|
{
|
|
dumptree((vsid->vsid<<28) | i << 20, vsid->tree[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void dumpmap()
|
|
{
|
|
int i,j;
|
|
ppc_map_t *map;
|
|
MmuVsidInfo *vsid;
|
|
fmtout("Address spaces:\n");
|
|
for (vsid = VsidHead; vsid; vsid = vsid->next)
|
|
{
|
|
dumpvsid(vsid);
|
|
}
|
|
}
|
|
|
|
void callkernel(void *fun_ptr, void *arg)
|
|
{
|
|
int i;
|
|
|
|
Booted = 1;
|
|
|
|
for (i = 0; i < 16; i++)
|
|
{
|
|
// Patch up the vsid map. We shouldn't muck with these until we're
|
|
// booted.
|
|
mmusetvsid(i, i+1, Vsid[i]);
|
|
}
|
|
|
|
void (*fun)(void *) = fun_ptr;
|
|
__asm__("mfmsr 3\n\t"
|
|
"ori 3,3,0x30\n\t"
|
|
"mtmsr 3\n\t"
|
|
"mtsdr1 %0\n\t"
|
|
"mr 0,%2\n\t"
|
|
"mtctr 0\n\t"
|
|
"mr 3,%1\n\t"
|
|
"bctrl\n\t"
|
|
: : "r" (HTABORG), "r" (arg), "r" (fun));
|
|
/* BYE ! */
|
|
}
|