Full MIPS64 MMU implementation
PATCH 1/1 Full MIPS64 MMU implementation
Hi all,
The patch below finally adds full support for MIPS64 MMU. With it I am able to boot a 64-bit MALTA kernel up to a kernel panic, as it does not detect any devices. There is probably a bug somewhere in map_address().
Note that the long hardcoded masks are a bit ugly, but I am working on a patch to add a per-CPU SEGBITS value.
Cheers,
Aurelien
helper.c +46 -5
@@ -50,6 +50,9 @@target_ulong mask = tlb->PageMask | ~(TARGET_PAGE_MASK <<1 );target_ulong tag = address & ~mask;target_ulong VPN = tlb->VPN & ~mask; +#ifdef TARGET_MIPS64 + tag &=0xC00000FFFFFFFFFFULL ; +#endif /* Check ASID, virtual page number & size */ if ((tlb->G ==1 || tlb->ASID ==ASID ) &&VPN == tag) {
@@ -285,10 +288,16 @@ }/* Raise exception */ env->CP0_BadVAddr = address; - env->CP0_Context = (env->CP0_Context &0xff800000 ) | + env->CP0_Context = (env->CP0_Context & ~0x007fffff ) | ((address >>9 ) &0x007ffff0 ); env->CP0_EntryHi = (env->CP0_EntryHi &0xFF ) | (address & (TARGET_PAGE_MASK <<1 )); +#ifdef TARGET_MIPS64 + env->CP0_EntryHi &=0xc00000ffffffffffULL ; + env->CP0_XContext = (env->CP0_XContext &0xfffffffe00000000ULL ) | + ((address >>31 ) &0x0000000180000000ULL ) | + ((address >>9 ) &0x000000007ffffff0ULL ); +#endif env->exception_index = exception; env->error_code = error_code; ret =1 ;
@@ -401,8 +410,19 @@ goto set_EPC;case EXCP_TLBL : cause =2 ; -if (env->error_code ==1 && !(env->CP0_Status & (1 << CP0St_EXL))) - offset =0x000 ; +if (env->error_code ==1 && !(env->CP0_Status & (1 << CP0St_EXL))) { +#ifdef TARGET_MIPS64 +int R = env->CP0_BadVAddr >>62 ; +int UX = (env->CP0_Status & (1 << CP0St_UX)) !=0 ; +int SX = (env->CP0_Status & (1 << CP0St_SX)) !=0 ; +int KX = (env->CP0_Status & (1 << CP0St_KX)) !=0 ; + +if ((R ==0 &&UX ) || (R ==1 &&SX ) || (R ==3 &&KX )) + offset =0x080 ; + else +#endif + offset =0x000 ; + } goto set_EPC;case EXCP_IBE : cause =6 ;
@@ -438,8 +458,19 @@ goto set_EPC;case EXCP_TLBS : cause =3 ; -if (env->error_code ==1 && !(env->CP0_Status & (1 << CP0St_EXL))) - offset =0x000 ; +if (env->error_code ==1 && !(env->CP0_Status & (1 << CP0St_EXL))) { +#ifdef TARGET_MIPS64 +int R = env->CP0_BadVAddr >>62 ; +int UX = (env->CP0_Status & (1 << CP0St_UX)) !=0 ; +int SX = (env->CP0_Status & (1 << CP0St_SX)) !=0 ; +int KX = (env->CP0_Status & (1 << CP0St_KX)) !=0 ; + +if ((R ==0 &&UX ) || (R ==1 &&SX ) || (R ==3 &&KX )) + offset =0x080 ; + else +#endif + offset =0x000 ; + } set_EPC:if (!(env->CP0_Status & (1 << CP0St_EXL))) {if (env->hflags &MIPS_HFLAG_BMASK ) {
@@ -510,6 +541,11 @@ mask = tlb->PageMask | ~(TARGET_PAGE_MASK <<1 );if (tlb->V0) { addr = tlb->VPN & ~mask; +#ifdef TARGET_MIPS64 +if (addr >=0xC00000FF80000000ULL ) { + addr |=0x3FFFFF0000000000ULL ; + } +#endif end = addr | (mask >>1 );while (addr < end) {tlb_flush_page (env, addr);
@@ -518,6 +554,11 @@ }if (tlb->V1) { addr = (tlb->VPN & ~mask) | ((mask >>1 ) +1 ); +#ifdef TARGET_MIPS64 +if (addr >=0xC00000FF80000000ULL ) { + addr |=0x3FFFFF0000000000ULL ; + } +#endif end = addr | mask;while (addr < end) {tlb_flush_page (env, addr);
op.c +4 -2
@@ -1313,8 +1313,10 @@target_ulong old, val;/* 1k pages not implemented */ -/* Ignore MIPS64 TLB for now */ - val = (target_ulong )(int32_t )T0 & ~(target_ulong )0x1F00 ; + val =T0 & ((TARGET_PAGE_MASK <<1 ) |0xFF ); +#ifdef TARGET_MIPS64 + val =T0 &0xC00000FFFFFFFFFFULL ; +#endif old = env->CP0_EntryHi; env->CP0_EntryHi = val;/* If the ASID changes, flush qemu's TLB. */
op_helper.c +3 -0
@@ -412,6 +412,9 @@/* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */ tlb = &env->tlb[idx]; tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK <<1 ); +#ifdef TARGET_MIPS64 + tlb->VPN = env->CP0_EntryHi &0xC00000FFFFFFFFFFULL ; +#endif tlb->ASID = env->CP0_EntryHi &0xFF ; tlb->PageMask = env->CP0_PageMask; tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 &1 ;
Signature · 4 lines
.''`. Aurelien Jarno | GPG: 1024D/F1BCDB73 : :' : Debian developer | Electrical Engineer `. `' [email protected] | [email protected] `- people.debian.org/~aurel32 | www.aurel32.net