 5499b6ffac
			
		
	
	
		5499b6ffac
		
	
	
	
	
		
			
			The variable CP0_LLAddr represent the full lladdr, not the actual register value, which is only part of this value and depends on the CPU. Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
		
			
				
	
	
		
			309 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			309 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include "hw/hw.h"
 | |
| #include "hw/boards.h"
 | |
| 
 | |
| #include "exec-all.h"
 | |
| 
 | |
| static void save_tc(QEMUFile *f, TCState *tc)
 | |
| {
 | |
|     int i;
 | |
| 
 | |
|     /* Save active TC */
 | |
|     for(i = 0; i < 32; i++)
 | |
|         qemu_put_betls(f, &tc->gpr[i]);
 | |
|     qemu_put_betls(f, &tc->PC);
 | |
|     for(i = 0; i < MIPS_DSP_ACC; i++)
 | |
|         qemu_put_betls(f, &tc->HI[i]);
 | |
|     for(i = 0; i < MIPS_DSP_ACC; i++)
 | |
|         qemu_put_betls(f, &tc->LO[i]);
 | |
|     for(i = 0; i < MIPS_DSP_ACC; i++)
 | |
|         qemu_put_betls(f, &tc->ACX[i]);
 | |
|     qemu_put_betls(f, &tc->DSPControl);
 | |
|     qemu_put_sbe32s(f, &tc->CP0_TCStatus);
 | |
|     qemu_put_sbe32s(f, &tc->CP0_TCBind);
 | |
|     qemu_put_betls(f, &tc->CP0_TCHalt);
 | |
|     qemu_put_betls(f, &tc->CP0_TCContext);
 | |
|     qemu_put_betls(f, &tc->CP0_TCSchedule);
 | |
|     qemu_put_betls(f, &tc->CP0_TCScheFBack);
 | |
|     qemu_put_sbe32s(f, &tc->CP0_Debug_tcstatus);
 | |
| }
 | |
| 
 | |
| static void save_fpu(QEMUFile *f, CPUMIPSFPUContext *fpu)
 | |
| {
 | |
|     int i;
 | |
| 
 | |
|     for(i = 0; i < 32; i++)
 | |
|         qemu_put_be64s(f, &fpu->fpr[i].d);
 | |
|     qemu_put_s8s(f, &fpu->fp_status.float_detect_tininess);
 | |
|     qemu_put_s8s(f, &fpu->fp_status.float_rounding_mode);
 | |
|     qemu_put_s8s(f, &fpu->fp_status.float_exception_flags);
 | |
|     qemu_put_be32s(f, &fpu->fcr0);
 | |
|     qemu_put_be32s(f, &fpu->fcr31);
 | |
| }
 | |
| 
 | |
| void cpu_save(QEMUFile *f, void *opaque)
 | |
| {
 | |
|     CPUState *env = opaque;
 | |
|     int i;
 | |
| 
 | |
|     /* Save active TC */
 | |
|     save_tc(f, &env->active_tc);
 | |
| 
 | |
|     /* Save active FPU */
 | |
|     save_fpu(f, &env->active_fpu);
 | |
| 
 | |
|     /* Save MVP */
 | |
|     qemu_put_sbe32s(f, &env->mvp->CP0_MVPControl);
 | |
|     qemu_put_sbe32s(f, &env->mvp->CP0_MVPConf0);
 | |
|     qemu_put_sbe32s(f, &env->mvp->CP0_MVPConf1);
 | |
| 
 | |
|     /* Save TLB */
 | |
|     qemu_put_be32s(f, &env->tlb->nb_tlb);
 | |
|     qemu_put_be32s(f, &env->tlb->tlb_in_use);
 | |
|     for(i = 0; i < MIPS_TLB_MAX; i++) {
 | |
|         uint16_t flags = ((env->tlb->mmu.r4k.tlb[i].G << 10) |
 | |
|                           (env->tlb->mmu.r4k.tlb[i].C0 << 7) |
 | |
|                           (env->tlb->mmu.r4k.tlb[i].C1 << 4) |
 | |
|                           (env->tlb->mmu.r4k.tlb[i].V0 << 3) |
 | |
|                           (env->tlb->mmu.r4k.tlb[i].V1 << 2) |
 | |
|                           (env->tlb->mmu.r4k.tlb[i].D0 << 1) |
 | |
|                           (env->tlb->mmu.r4k.tlb[i].D1 << 0));
 | |
|         uint8_t asid;
 | |
| 
 | |
|         qemu_put_betls(f, &env->tlb->mmu.r4k.tlb[i].VPN);
 | |
|         qemu_put_be32s(f, &env->tlb->mmu.r4k.tlb[i].PageMask);
 | |
|         asid = env->tlb->mmu.r4k.tlb[i].ASID;
 | |
|         qemu_put_8s(f, &asid);
 | |
|         qemu_put_be16s(f, &flags);
 | |
|         qemu_put_betls(f, &env->tlb->mmu.r4k.tlb[i].PFN[0]);
 | |
|         qemu_put_betls(f, &env->tlb->mmu.r4k.tlb[i].PFN[1]);
 | |
|     }
 | |
| 
 | |
|     /* Save CPU metastate */
 | |
|     qemu_put_be32s(f, &env->current_tc);
 | |
|     qemu_put_be32s(f, &env->current_fpu);
 | |
|     qemu_put_sbe32s(f, &env->error_code);
 | |
|     qemu_put_be32s(f, &env->hflags);
 | |
|     qemu_put_betls(f, &env->btarget);
 | |
|     i = env->bcond;
 | |
|     qemu_put_sbe32s(f, &i);
 | |
| 
 | |
|     /* Save remaining CP1 registers */
 | |
|     qemu_put_sbe32s(f, &env->CP0_Index);
 | |
|     qemu_put_sbe32s(f, &env->CP0_Random);
 | |
|     qemu_put_sbe32s(f, &env->CP0_VPEControl);
 | |
|     qemu_put_sbe32s(f, &env->CP0_VPEConf0);
 | |
|     qemu_put_sbe32s(f, &env->CP0_VPEConf1);
 | |
|     qemu_put_betls(f, &env->CP0_YQMask);
 | |
|     qemu_put_betls(f, &env->CP0_VPESchedule);
 | |
|     qemu_put_betls(f, &env->CP0_VPEScheFBack);
 | |
|     qemu_put_sbe32s(f, &env->CP0_VPEOpt);
 | |
|     qemu_put_betls(f, &env->CP0_EntryLo0);
 | |
|     qemu_put_betls(f, &env->CP0_EntryLo1);
 | |
|     qemu_put_betls(f, &env->CP0_Context);
 | |
|     qemu_put_sbe32s(f, &env->CP0_PageMask);
 | |
|     qemu_put_sbe32s(f, &env->CP0_PageGrain);
 | |
|     qemu_put_sbe32s(f, &env->CP0_Wired);
 | |
|     qemu_put_sbe32s(f, &env->CP0_SRSConf0);
 | |
|     qemu_put_sbe32s(f, &env->CP0_SRSConf1);
 | |
|     qemu_put_sbe32s(f, &env->CP0_SRSConf2);
 | |
|     qemu_put_sbe32s(f, &env->CP0_SRSConf3);
 | |
|     qemu_put_sbe32s(f, &env->CP0_SRSConf4);
 | |
|     qemu_put_sbe32s(f, &env->CP0_HWREna);
 | |
|     qemu_put_betls(f, &env->CP0_BadVAddr);
 | |
|     qemu_put_sbe32s(f, &env->CP0_Count);
 | |
|     qemu_put_betls(f, &env->CP0_EntryHi);
 | |
|     qemu_put_sbe32s(f, &env->CP0_Compare);
 | |
|     qemu_put_sbe32s(f, &env->CP0_Status);
 | |
|     qemu_put_sbe32s(f, &env->CP0_IntCtl);
 | |
|     qemu_put_sbe32s(f, &env->CP0_SRSCtl);
 | |
|     qemu_put_sbe32s(f, &env->CP0_SRSMap);
 | |
|     qemu_put_sbe32s(f, &env->CP0_Cause);
 | |
|     qemu_put_betls(f, &env->CP0_EPC);
 | |
|     qemu_put_sbe32s(f, &env->CP0_PRid);
 | |
|     qemu_put_sbe32s(f, &env->CP0_EBase);
 | |
|     qemu_put_sbe32s(f, &env->CP0_Config0);
 | |
|     qemu_put_sbe32s(f, &env->CP0_Config1);
 | |
|     qemu_put_sbe32s(f, &env->CP0_Config2);
 | |
|     qemu_put_sbe32s(f, &env->CP0_Config3);
 | |
|     qemu_put_sbe32s(f, &env->CP0_Config6);
 | |
|     qemu_put_sbe32s(f, &env->CP0_Config7);
 | |
|     qemu_put_betls(f, &env->lladdr);
 | |
|     for(i = 0; i < 8; i++)
 | |
|         qemu_put_betls(f, &env->CP0_WatchLo[i]);
 | |
|     for(i = 0; i < 8; i++)
 | |
|         qemu_put_sbe32s(f, &env->CP0_WatchHi[i]);
 | |
|     qemu_put_betls(f, &env->CP0_XContext);
 | |
|     qemu_put_sbe32s(f, &env->CP0_Framemask);
 | |
|     qemu_put_sbe32s(f, &env->CP0_Debug);
 | |
|     qemu_put_betls(f, &env->CP0_DEPC);
 | |
|     qemu_put_sbe32s(f, &env->CP0_Performance0);
 | |
|     qemu_put_sbe32s(f, &env->CP0_TagLo);
 | |
|     qemu_put_sbe32s(f, &env->CP0_DataLo);
 | |
|     qemu_put_sbe32s(f, &env->CP0_TagHi);
 | |
|     qemu_put_sbe32s(f, &env->CP0_DataHi);
 | |
|     qemu_put_betls(f, &env->CP0_ErrorEPC);
 | |
|     qemu_put_sbe32s(f, &env->CP0_DESAVE);
 | |
| 
 | |
|     /* Save inactive TC state */
 | |
|     for (i = 0; i < MIPS_SHADOW_SET_MAX; i++)
 | |
|         save_tc(f, &env->tcs[i]);
 | |
|     for (i = 0; i < MIPS_FPU_MAX; i++)
 | |
|         save_fpu(f, &env->fpus[i]);
 | |
| }
 | |
| 
 | |
| static void load_tc(QEMUFile *f, TCState *tc)
 | |
| {
 | |
|     int i;
 | |
| 
 | |
|     /* Save active TC */
 | |
|     for(i = 0; i < 32; i++)
 | |
|         qemu_get_betls(f, &tc->gpr[i]);
 | |
|     qemu_get_betls(f, &tc->PC);
 | |
|     for(i = 0; i < MIPS_DSP_ACC; i++)
 | |
|         qemu_get_betls(f, &tc->HI[i]);
 | |
|     for(i = 0; i < MIPS_DSP_ACC; i++)
 | |
|         qemu_get_betls(f, &tc->LO[i]);
 | |
|     for(i = 0; i < MIPS_DSP_ACC; i++)
 | |
|         qemu_get_betls(f, &tc->ACX[i]);
 | |
|     qemu_get_betls(f, &tc->DSPControl);
 | |
|     qemu_get_sbe32s(f, &tc->CP0_TCStatus);
 | |
|     qemu_get_sbe32s(f, &tc->CP0_TCBind);
 | |
|     qemu_get_betls(f, &tc->CP0_TCHalt);
 | |
|     qemu_get_betls(f, &tc->CP0_TCContext);
 | |
|     qemu_get_betls(f, &tc->CP0_TCSchedule);
 | |
|     qemu_get_betls(f, &tc->CP0_TCScheFBack);
 | |
|     qemu_get_sbe32s(f, &tc->CP0_Debug_tcstatus);
 | |
| }
 | |
| 
 | |
| static void load_fpu(QEMUFile *f, CPUMIPSFPUContext *fpu)
 | |
| {
 | |
|     int i;
 | |
| 
 | |
|     for(i = 0; i < 32; i++)
 | |
|         qemu_get_be64s(f, &fpu->fpr[i].d);
 | |
|     qemu_get_s8s(f, &fpu->fp_status.float_detect_tininess);
 | |
|     qemu_get_s8s(f, &fpu->fp_status.float_rounding_mode);
 | |
|     qemu_get_s8s(f, &fpu->fp_status.float_exception_flags);
 | |
|     qemu_get_be32s(f, &fpu->fcr0);
 | |
|     qemu_get_be32s(f, &fpu->fcr31);
 | |
| }
 | |
| 
 | |
| int cpu_load(QEMUFile *f, void *opaque, int version_id)
 | |
| {
 | |
|     CPUState *env = opaque;
 | |
|     int i;
 | |
| 
 | |
|     if (version_id != 3)
 | |
|         return -EINVAL;
 | |
| 
 | |
|     /* Load active TC */
 | |
|     load_tc(f, &env->active_tc);
 | |
| 
 | |
|     /* Load active FPU */
 | |
|     load_fpu(f, &env->active_fpu);
 | |
| 
 | |
|     /* Load MVP */
 | |
|     qemu_get_sbe32s(f, &env->mvp->CP0_MVPControl);
 | |
|     qemu_get_sbe32s(f, &env->mvp->CP0_MVPConf0);
 | |
|     qemu_get_sbe32s(f, &env->mvp->CP0_MVPConf1);
 | |
| 
 | |
|     /* Load TLB */
 | |
|     qemu_get_be32s(f, &env->tlb->nb_tlb);
 | |
|     qemu_get_be32s(f, &env->tlb->tlb_in_use);
 | |
|     for(i = 0; i < MIPS_TLB_MAX; i++) {
 | |
|         uint16_t flags;
 | |
|         uint8_t asid;
 | |
| 
 | |
|         qemu_get_betls(f, &env->tlb->mmu.r4k.tlb[i].VPN);
 | |
|         qemu_get_be32s(f, &env->tlb->mmu.r4k.tlb[i].PageMask);
 | |
|         qemu_get_8s(f, &asid);
 | |
|         env->tlb->mmu.r4k.tlb[i].ASID = asid;
 | |
|         qemu_get_be16s(f, &flags);
 | |
|         env->tlb->mmu.r4k.tlb[i].G = (flags >> 10) & 1;
 | |
|         env->tlb->mmu.r4k.tlb[i].C0 = (flags >> 7) & 3;
 | |
|         env->tlb->mmu.r4k.tlb[i].C1 = (flags >> 4) & 3;
 | |
|         env->tlb->mmu.r4k.tlb[i].V0 = (flags >> 3) & 1;
 | |
|         env->tlb->mmu.r4k.tlb[i].V1 = (flags >> 2) & 1;
 | |
|         env->tlb->mmu.r4k.tlb[i].D0 = (flags >> 1) & 1;
 | |
|         env->tlb->mmu.r4k.tlb[i].D1 = (flags >> 0) & 1;
 | |
|         qemu_get_betls(f, &env->tlb->mmu.r4k.tlb[i].PFN[0]);
 | |
|         qemu_get_betls(f, &env->tlb->mmu.r4k.tlb[i].PFN[1]);
 | |
|     }
 | |
| 
 | |
|     /* Load CPU metastate */
 | |
|     qemu_get_be32s(f, &env->current_tc);
 | |
|     qemu_get_be32s(f, &env->current_fpu);
 | |
|     qemu_get_sbe32s(f, &env->error_code);
 | |
|     qemu_get_be32s(f, &env->hflags);
 | |
|     qemu_get_betls(f, &env->btarget);
 | |
|     qemu_get_sbe32s(f, &i);
 | |
|     env->bcond = i;
 | |
| 
 | |
|     /* Load remaining CP1 registers */
 | |
|     qemu_get_sbe32s(f, &env->CP0_Index);
 | |
|     qemu_get_sbe32s(f, &env->CP0_Random);
 | |
|     qemu_get_sbe32s(f, &env->CP0_VPEControl);
 | |
|     qemu_get_sbe32s(f, &env->CP0_VPEConf0);
 | |
|     qemu_get_sbe32s(f, &env->CP0_VPEConf1);
 | |
|     qemu_get_betls(f, &env->CP0_YQMask);
 | |
|     qemu_get_betls(f, &env->CP0_VPESchedule);
 | |
|     qemu_get_betls(f, &env->CP0_VPEScheFBack);
 | |
|     qemu_get_sbe32s(f, &env->CP0_VPEOpt);
 | |
|     qemu_get_betls(f, &env->CP0_EntryLo0);
 | |
|     qemu_get_betls(f, &env->CP0_EntryLo1);
 | |
|     qemu_get_betls(f, &env->CP0_Context);
 | |
|     qemu_get_sbe32s(f, &env->CP0_PageMask);
 | |
|     qemu_get_sbe32s(f, &env->CP0_PageGrain);
 | |
|     qemu_get_sbe32s(f, &env->CP0_Wired);
 | |
|     qemu_get_sbe32s(f, &env->CP0_SRSConf0);
 | |
|     qemu_get_sbe32s(f, &env->CP0_SRSConf1);
 | |
|     qemu_get_sbe32s(f, &env->CP0_SRSConf2);
 | |
|     qemu_get_sbe32s(f, &env->CP0_SRSConf3);
 | |
|     qemu_get_sbe32s(f, &env->CP0_SRSConf4);
 | |
|     qemu_get_sbe32s(f, &env->CP0_HWREna);
 | |
|     qemu_get_betls(f, &env->CP0_BadVAddr);
 | |
|     qemu_get_sbe32s(f, &env->CP0_Count);
 | |
|     qemu_get_betls(f, &env->CP0_EntryHi);
 | |
|     qemu_get_sbe32s(f, &env->CP0_Compare);
 | |
|     qemu_get_sbe32s(f, &env->CP0_Status);
 | |
|     qemu_get_sbe32s(f, &env->CP0_IntCtl);
 | |
|     qemu_get_sbe32s(f, &env->CP0_SRSCtl);
 | |
|     qemu_get_sbe32s(f, &env->CP0_SRSMap);
 | |
|     qemu_get_sbe32s(f, &env->CP0_Cause);
 | |
|     qemu_get_betls(f, &env->CP0_EPC);
 | |
|     qemu_get_sbe32s(f, &env->CP0_PRid);
 | |
|     qemu_get_sbe32s(f, &env->CP0_EBase);
 | |
|     qemu_get_sbe32s(f, &env->CP0_Config0);
 | |
|     qemu_get_sbe32s(f, &env->CP0_Config1);
 | |
|     qemu_get_sbe32s(f, &env->CP0_Config2);
 | |
|     qemu_get_sbe32s(f, &env->CP0_Config3);
 | |
|     qemu_get_sbe32s(f, &env->CP0_Config6);
 | |
|     qemu_get_sbe32s(f, &env->CP0_Config7);
 | |
|     qemu_get_betls(f, &env->lladdr);
 | |
|     for(i = 0; i < 8; i++)
 | |
|         qemu_get_betls(f, &env->CP0_WatchLo[i]);
 | |
|     for(i = 0; i < 8; i++)
 | |
|         qemu_get_sbe32s(f, &env->CP0_WatchHi[i]);
 | |
|     qemu_get_betls(f, &env->CP0_XContext);
 | |
|     qemu_get_sbe32s(f, &env->CP0_Framemask);
 | |
|     qemu_get_sbe32s(f, &env->CP0_Debug);
 | |
|     qemu_get_betls(f, &env->CP0_DEPC);
 | |
|     qemu_get_sbe32s(f, &env->CP0_Performance0);
 | |
|     qemu_get_sbe32s(f, &env->CP0_TagLo);
 | |
|     qemu_get_sbe32s(f, &env->CP0_DataLo);
 | |
|     qemu_get_sbe32s(f, &env->CP0_TagHi);
 | |
|     qemu_get_sbe32s(f, &env->CP0_DataHi);
 | |
|     qemu_get_betls(f, &env->CP0_ErrorEPC);
 | |
|     qemu_get_sbe32s(f, &env->CP0_DESAVE);
 | |
| 
 | |
|     /* Load inactive TC state */
 | |
|     for (i = 0; i < MIPS_SHADOW_SET_MAX; i++)
 | |
|         load_tc(f, &env->tcs[i]);
 | |
|     for (i = 0; i < MIPS_FPU_MAX; i++)
 | |
|         load_fpu(f, &env->fpus[i]);
 | |
| 
 | |
|     /* XXX: ensure compatiblity for halted bit ? */
 | |
|     tlb_flush(env, 1);
 | |
|     return 0;
 | |
| }
 |