Full MIPS64 MMU implementation, by Aurelien Jarno.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2820 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
		
							parent
							
								
									f1b0aa5de7
								
							
						
					
					
						commit
						100ce98812
					
				@ -76,6 +76,9 @@ int r4k_map_address (CPUState *env, target_ulong *physical, int *prot,
 | 
				
			|||||||
        target_ulong mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
 | 
					        target_ulong mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
 | 
				
			||||||
        target_ulong tag = address & ~mask;
 | 
					        target_ulong tag = address & ~mask;
 | 
				
			||||||
        target_ulong VPN = tlb->VPN & ~mask;
 | 
					        target_ulong VPN = tlb->VPN & ~mask;
 | 
				
			||||||
 | 
					#ifdef TARGET_MIPS64
 | 
				
			||||||
 | 
					        tag &= 0xC00000FFFFFFFFFFULL;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* Check ASID, virtual page number & size */
 | 
					        /* Check ASID, virtual page number & size */
 | 
				
			||||||
        if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
 | 
					        if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
 | 
				
			||||||
@ -295,10 +298,16 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        /* Raise exception */
 | 
					        /* Raise exception */
 | 
				
			||||||
        env->CP0_BadVAddr = address;
 | 
					        env->CP0_BadVAddr = address;
 | 
				
			||||||
        env->CP0_Context = (env->CP0_Context & 0xff800000) |
 | 
					        env->CP0_Context = (env->CP0_Context & ~0x007fffff) |
 | 
				
			||||||
	                   ((address >> 9) &   0x007ffff0);
 | 
						                   ((address >> 9) &   0x007ffff0);
 | 
				
			||||||
        env->CP0_EntryHi =
 | 
					        env->CP0_EntryHi =
 | 
				
			||||||
            (env->CP0_EntryHi & 0xFF) | (address & (TARGET_PAGE_MASK << 1));
 | 
					            (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->exception_index = exception;
 | 
				
			||||||
        env->error_code = error_code;
 | 
					        env->error_code = error_code;
 | 
				
			||||||
        ret = 1;
 | 
					        ret = 1;
 | 
				
			||||||
@ -411,8 +420,19 @@ void do_interrupt (CPUState *env)
 | 
				
			|||||||
        goto set_EPC;
 | 
					        goto set_EPC;
 | 
				
			||||||
    case EXCP_TLBL:
 | 
					    case EXCP_TLBL:
 | 
				
			||||||
        cause = 2;
 | 
					        cause = 2;
 | 
				
			||||||
        if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL)))
 | 
					        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;
 | 
					                offset = 0x000;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        goto set_EPC;
 | 
					        goto set_EPC;
 | 
				
			||||||
    case EXCP_IBE:
 | 
					    case EXCP_IBE:
 | 
				
			||||||
        cause = 6;
 | 
					        cause = 6;
 | 
				
			||||||
@ -448,8 +468,19 @@ void do_interrupt (CPUState *env)
 | 
				
			|||||||
        goto set_EPC;
 | 
					        goto set_EPC;
 | 
				
			||||||
    case EXCP_TLBS:
 | 
					    case EXCP_TLBS:
 | 
				
			||||||
        cause = 3;
 | 
					        cause = 3;
 | 
				
			||||||
        if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL)))
 | 
					        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;
 | 
					                offset = 0x000;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    set_EPC:
 | 
					    set_EPC:
 | 
				
			||||||
        if (!(env->CP0_Status & (1 << CP0St_EXL))) {
 | 
					        if (!(env->CP0_Status & (1 << CP0St_EXL))) {
 | 
				
			||||||
            if (env->hflags & MIPS_HFLAG_BMASK) {
 | 
					            if (env->hflags & MIPS_HFLAG_BMASK) {
 | 
				
			||||||
@ -520,6 +551,11 @@ void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra)
 | 
				
			|||||||
    mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
 | 
					    mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
 | 
				
			||||||
    if (tlb->V0) {
 | 
					    if (tlb->V0) {
 | 
				
			||||||
        addr = tlb->VPN & ~mask;
 | 
					        addr = tlb->VPN & ~mask;
 | 
				
			||||||
 | 
					#ifdef TARGET_MIPS64
 | 
				
			||||||
 | 
					        if (addr >= 0xC00000FF80000000ULL) {
 | 
				
			||||||
 | 
					            addr |= 0x3FFFFF0000000000ULL;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
        end = addr | (mask >> 1);
 | 
					        end = addr | (mask >> 1);
 | 
				
			||||||
        while (addr < end) {
 | 
					        while (addr < end) {
 | 
				
			||||||
            tlb_flush_page (env, addr);
 | 
					            tlb_flush_page (env, addr);
 | 
				
			||||||
@ -528,6 +564,11 @@ void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    if (tlb->V1) {
 | 
					    if (tlb->V1) {
 | 
				
			||||||
        addr = (tlb->VPN & ~mask) | ((mask >> 1) + 1);
 | 
					        addr = (tlb->VPN & ~mask) | ((mask >> 1) + 1);
 | 
				
			||||||
 | 
					#ifdef TARGET_MIPS64
 | 
				
			||||||
 | 
					        if (addr >= 0xC00000FF80000000ULL) {
 | 
				
			||||||
 | 
					            addr |= 0x3FFFFF0000000000ULL;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
        end = addr | mask;
 | 
					        end = addr | mask;
 | 
				
			||||||
        while (addr < end) {
 | 
					        while (addr < end) {
 | 
				
			||||||
            tlb_flush_page (env, addr);
 | 
					            tlb_flush_page (env, addr);
 | 
				
			||||||
 | 
				
			|||||||
@ -1317,8 +1317,10 @@ void op_mtc0_entryhi (void)
 | 
				
			|||||||
    target_ulong old, val;
 | 
					    target_ulong old, val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* 1k pages not implemented */
 | 
					    /* 1k pages not implemented */
 | 
				
			||||||
    /* Ignore MIPS64 TLB for now */
 | 
					    val = T0 & ((TARGET_PAGE_MASK << 1) | 0xFF);
 | 
				
			||||||
    val = (target_ulong)(int32_t)T0 & ~(target_ulong)0x1F00;
 | 
					#ifdef TARGET_MIPS64
 | 
				
			||||||
 | 
					    val = T0 & 0xC00000FFFFFFFFFFULL;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
    old = env->CP0_EntryHi;
 | 
					    old = env->CP0_EntryHi;
 | 
				
			||||||
    env->CP0_EntryHi = val;
 | 
					    env->CP0_EntryHi = val;
 | 
				
			||||||
    /* If the ASID changes, flush qemu's TLB.  */
 | 
					    /* If the ASID changes, flush qemu's TLB.  */
 | 
				
			||||||
 | 
				
			|||||||
@ -391,6 +391,9 @@ static void r4k_fill_tlb (int idx)
 | 
				
			|||||||
    /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
 | 
					    /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
 | 
				
			||||||
    tlb = &env->mmu.r4k.tlb[idx];
 | 
					    tlb = &env->mmu.r4k.tlb[idx];
 | 
				
			||||||
    tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
 | 
					    tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
 | 
				
			||||||
 | 
					#ifdef TARGET_MIPS64
 | 
				
			||||||
 | 
					    tlb->VPN &= 0xC00000FFFFFFFFFFULL;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
    tlb->ASID = env->CP0_EntryHi & 0xFF;
 | 
					    tlb->ASID = env->CP0_EntryHi & 0xFF;
 | 
				
			||||||
    tlb->PageMask = env->CP0_PageMask;
 | 
					    tlb->PageMask = env->CP0_PageMask;
 | 
				
			||||||
    tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
 | 
					    tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user