#include "ppcmmu/mmu.h" #include "ppcmmu/mmuutil.h" inline int GetMSR() { register int res asm ("r3"); __asm__("mfmsr 3"); return res; } inline int GetDEC() { register int res asm ("r3"); __asm__("mfdec 3"); return res; } __asm__("\t.globl GetPhys\n" "GetPhys:\t\n" "mflr 0\n\t" "stwu 0,-16(1)\n\t" "mfmsr 5\n\t" "andi. 6,5,0xffef\n\t"/* turn off MSR[DR] */ "mtmsr 6\n\t" "isync\n\t" "sync\n\t" "lwz 3,0(3)\n\t" /* Get actual value at phys addr r3 */ "mtmsr 5\n\t" "isync\n\t" "sync\n\t" "lwz 0,0(1)\n\t" "addi 1,1,16\n\t" "mtlr 0\n\t" "blr" ); __asm__("\t.globl GetPhysHalf\n" "GetPhysHalf:\t\n" "mflr 0\n\t" "stwu 0,-16(1)\n\t" "mfmsr 5\n\t" "andi. 6,5,0xffef\n\t"/* turn off MSR[DR] */ "mtmsr 6\n\t" "isync\n\t" "sync\n\t" "lhz 3,0(3)\n\t" /* Get actual value at phys addr r3 */ "mtmsr 5\n\t" "isync\n\t" "sync\n\t" "lwz 0,0(1)\n\t" "addi 1,1,16\n\t" "mtlr 0\n\t" "blr" ); __asm__("\t.globl GetPhysByte\n" "GetPhysByte:\t\n" "mflr 0\n\t" "stwu 0,-16(1)\n\t" "mfmsr 5\n\t" "andi. 6,5,0xffef\n\t"/* turn off MSR[DR] */ "mtmsr 6\n\t" "isync\n\t" "sync\n\t" "lbz 3,0(3)\n\t" /* Get actual value at phys addr r3 */ "mtmsr 5\n\t" "isync\n\t" "sync\n\t" "lwz 0,0(1)\n\t" "addi 1,1,16\n\t" "mtlr 0\n\t" "blr" ); __asm__("\t.globl SetPhys\n" "SetPhys:\t\n" "mflr 0\n\t" "stwu 0,-16(1)\n\t" "mfmsr 5\n\t" "andi. 6,5,0xffef\n\t"/* turn off MSR[DR] */ "mtmsr 6\n\t" "sync\n\t" "eieio\n\t" "stw 4,0(3)\n\t" /* Set actual value at phys addr r3 */ "dcbst 0,3\n\t" "mtmsr 5\n\t" "sync\n\t" "eieio\n\t" "mr 3,4\n\t" "lwz 0,0(1)\n\t" "addi 1,1,16\n\t" "mtlr 0\n\t" "blr" ); __asm__("\t.globl SetPhysHalf\n" "SetPhysHalf:\t\n" "mflr 0\n\t" "stwu 0,-16(1)\n\t" "mfmsr 5\n\t" "andi. 6,5,0xffef\n\t"/* turn off MSR[DR] */ "mtmsr 6\n\t" "sync\n\t" "eieio\n\t" "sth 4,0(3)\n\t" /* Set actual value at phys addr r3 */ "dcbst 0,3\n\t" "mtmsr 5\n\t" "sync\n\t" "eieio\n\t" "mr 3,4\n\t" "lwz 0,0(1)\n\t" "addi 1,1,16\n\t" "mtlr 0\n\t" "blr" ); __asm__("\t.globl SetPhysByte\n" "SetPhysByte:\t\n" "mflr 0\n\t" "stwu 0,-16(1)\n\t" "mfmsr 5\n\t" "andi. 6,5,0xffef\n\t"/* turn off MSR[DR] */ "mtmsr 6\n\t" "sync\n\t" "eieio\n\t" "stb 4,0(3)\n\t" /* Set actual value at phys addr r3 */ "dcbst 0,3\n\t" "mtmsr 5\n\t" "sync\n\t" "eieio\n\t" "mr 3,4\n\t" "lwz 0,0(1)\n\t" "addi 1,1,16\n\t" "mtlr 0\n\t" "blr" ); inline int GetSR(int n) { register int res = 0; switch( n ) { case 0: __asm__("mfsr %0,0" : "=r" (res)); break; case 1: __asm__("mfsr %0,1" : "=r" (res)); break; case 2: __asm__("mfsr %0,2" : "=r" (res)); break; case 3: __asm__("mfsr %0,3" : "=r" (res)); break; case 4: __asm__("mfsr %0,4" : "=r" (res)); break; case 5: __asm__("mfsr %0,5" : "=r" (res)); break; case 6: __asm__("mfsr %0,6" : "=r" (res)); break; case 7: __asm__("mfsr %0,7" : "=r" (res)); break; case 8: __asm__("mfsr %0,8" : "=r" (res)); break; case 9: __asm__("mfsr %0,9" : "=r" (res)); break; case 10: __asm__("mfsr %0,10" : "=r" (res)); break; case 11: __asm__("mfsr %0,11" : "=r" (res)); break; case 12: __asm__("mfsr %0,12" : "=r" (res)); break; case 13: __asm__("mfsr %0,13" : "=r" (res)); break; case 14: __asm__("mfsr %0,14" : "=r" (res)); break; case 15: __asm__("mfsr %0,15" : "=r" (res)); break; } return res; } inline void SetSR(int n, int val) { switch( n ) { case 0: __asm__("mtsr 0,%0" : : "r" (val)); break; case 1: __asm__("mtsr 1,%0" : : "r" (val)); break; case 2: __asm__("mtsr 2,%0" : : "r" (val)); break; case 3: __asm__("mtsr 3,%0" : : "r" (val)); break; case 4: __asm__("mtsr 4,%0" : : "r" (val)); break; case 5: __asm__("mtsr 5,%0" : : "r" (val)); break; case 6: __asm__("mtsr 6,%0" : : "r" (val)); break; case 7: __asm__("mtsr 7,%0" : : "r" (val)); break; case 8: __asm__("mtsr 8,%0" : : "r" (val)); break; case 9: __asm__("mtsr 9,%0" : : "r" (val)); break; case 10: __asm__("mtsr 10,%0" : : "r" (val)); break; case 11: __asm__("mtsr 11,%0" : : "r" (val)); break; case 12: __asm__("mtsr 12,%0" : : "r" (val)); break; case 13: __asm__("mtsr 13,%0" : : "r" (val)); break; case 14: __asm__("mtsr 14,%0" : : "r" (val)); break; case 15: __asm__("mtsr 15,%0" : : "r" (val)); break; } } void GetBat( int bat, int inst, int *batHi, int *batLo ) { register int bh asm("r3"), bl asm("r4"); if( inst ) { switch( bat ) { case 0: __asm__("mfibatu 3,0"); __asm__("mfibatl 4,0"); break; case 1: __asm__("mfibatu 3,1"); __asm__("mfibatl 4,1"); break; case 2: __asm__("mfibatu 3,2"); __asm__("mfibatl 4,2"); break; case 3: __asm__("mfibatu 3,3"); __asm__("mfibatl 4,3"); break; } } else { switch( bat ) { case 0: __asm__("mfdbatu 3,0"); __asm__("mfdbatl 4,0"); break; case 1: __asm__("mfdbatu 3,1"); __asm__("mfdbatl 4,1"); break; case 2: __asm__("mfdbatu 3,2"); __asm__("mfdbatl 4,2"); break; case 3: __asm__("mfdbatu 3,3"); __asm__("mfdbatl 4,3"); break; } } *batHi = bh; *batLo = bl; } #define BATSET(n,t) \ case n: __asm__("mt" #t "batu " #n ",%0\n\tmt" #t "batl " #n ",%1" \ : : "r" (batHi), "r" (batLo)); break; void SetBat( int bat, int inst, int batHi, int batLo ) { if( inst ) { switch( bat ) { BATSET(0,i); BATSET(1,i); BATSET(2,i); BATSET(3,i); } } else { switch( bat ) { BATSET(0,d); BATSET(1,d); BATSET(2,d); BATSET(3,d); } } __asm__("isync\n\tsync"); } inline int GetSDR1() { register int res asm("r3"); __asm__("mfsdr1 3"); return res; } inline void SetSDR1( int sdr ) { int i,j; __asm__("mtsdr1 3"); __asm__("sync"); __asm__("isync"); for( i = 0; i < 256; i++ ) { j = i << 12; __asm__("tlbie %0,0" : : "r" (j)); } __asm__("eieio"); __asm__("tlbsync"); __asm__("ptesync"); } inline int BatTranslate( int batu, int batl, int virt ) { int mask; if(batu & 0x3fc) { mask = ~(0x1ffff | ((batu & 0x3fc)>>2)<<17); if((batu & 2) && ((batu & mask) == (virt & mask))) return (batl & mask) | (virt & ~mask); } else { mask = ~(0x1ffff | (batl << 17)); if(!(batl & 0x40) || ((batu & mask) != (virt & mask))) return (batl & mask) | (virt & ~mask); } return -1; } inline int BatHit( int batu, int batl, int virt ) { return BatTranslate( batu, batl, virt ) != -1; } /* translate address */ int PpcVirt2phys( vaddr_t virt, int inst ) { int msr = GetMSR(); int txmask = inst ? 0x20 : 0x10; int i, bath, batl, sr, sdr1, physbase, vahi, valo; int npteg, hash, hashmask, ptehi, ptelo, ptegaddr; int vsid, pteh, ptevsid, pteapi; if( msr & txmask ) { sr = GetSR( virt >> 28 ); vsid = sr & 0xfffffff; vahi = vsid >> 4; valo = (vsid << 28) | (virt & 0xfffffff); if( sr & 0x80000000 ) { return valo; } for( i = 0; i < 4; i++ ) { GetBat( i, inst, &bath, &batl ); if( BatHit( bath, batl, virt ) ) { return BatTranslate( bath, batl, virt ); } } sdr1 = GetSDR1(); physbase = sdr1 & ~0xffff; hashmask = ((sdr1 & 0x1ff) << 10) | 0x3ff; hash = (vsid & 0x7ffff) ^ ((valo >> 12) & 0xffff); npteg = hashmask + 1; for( pteh = 0; pteh < 0x80; pteh += 64, hash ^= 0x7ffff ) { ptegaddr = ((hashmask & hash) * 64) + physbase; for( i = 0; i < 8; i++ ) { ptehi = GetPhys( ptegaddr + (i * 8) ); ptelo = GetPhys( ptegaddr + (i * 8) + 4 ); ptevsid = (ptehi >> 7) & 0xffffff; pteapi = ptehi & 0x3f; if( (ptehi & 64) != pteh ) continue; if( ptevsid != (vsid & 0xffffff) ) continue; if( pteapi != ((virt >> 22) & 0x3f) ) continue; return (ptelo & 0xfffff000) | (virt & 0xfff); } } return -1; } else { return virt; } } int PtegNumber(vaddr_t virt, int hfun) { int sr = GetSR( (virt >> 28) & 0xf ); int vsid = sr & PPC_VSID_MASK; return ((((vsid & 0x7ffff) ^ ((virt >> 12) & 0xffff)) ^ (hfun ? -1 : 0)) & ((HTABSIZ - 1) >> 3) & 0x3ff); }