diff options
author | j_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162> | 2007-03-31 12:57:57 +0000 |
---|---|---|
committer | j_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162> | 2007-03-31 12:57:57 +0000 |
commit | c62db10577295ed4dc26fa9acd6e6f30cea7ffd0 (patch) | |
tree | 2e6f9a8d4ea556ffe7ff5fc079b021ae59bfa723 /target-ppc | |
parent | 636aaad7b5ab72c03451296412249352817167a9 (diff) |
Support for PowerPC BookE exception model.
No need to requeue timer exceptions.
Fix nip saving for 64 bits PowerPC.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2556 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-ppc')
-rw-r--r-- | target-ppc/helper.c | 141 |
1 files changed, 92 insertions, 49 deletions
diff --git a/target-ppc/helper.c b/target-ppc/helper.c index c541e7128b..1d973dc43b 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1340,11 +1340,12 @@ void ppc_store_msr_32 (CPUPPCState *env, uint32_t value) void do_compute_hflags (CPUPPCState *env) { /* Compute current hflags */ - env->hflags = (msr_pr << MSR_PR) | (msr_le << MSR_LE) | - (msr_fp << MSR_FP) | (msr_fe0 << MSR_FE0) | (msr_fe1 << MSR_FE1) | - (msr_vr << MSR_VR) | (msr_ap << MSR_AP) | (msr_sa << MSR_SA) | - (msr_se << MSR_SE) | (msr_be << MSR_BE); + env->hflags = (msr_cm << MSR_CM) | (msr_vr << MSR_VR) | + (msr_ap << MSR_AP) | (msr_sa << MSR_SA) | (msr_pr << MSR_PR) | + (msr_fp << MSR_FP) | (msr_fe0 << MSR_FE0) | (msr_se << MSR_SE) | + (msr_be << MSR_BE) | (msr_fe1 << MSR_FE1) | (msr_le << MSR_LE); #if defined (TARGET_PPC64) + /* No care here: PowerPC 64 MSR_SF means the same as MSR_CM for BookE */ env->hflags |= (msr_sf << (MSR_SF - 32)) | (msr_hv << (MSR_HV - 32)); #endif } @@ -1374,14 +1375,16 @@ static void dump_syscall(CPUState *env) void do_interrupt (CPUState *env) { - target_ulong msr, *srr_0, *srr_1; - int excp; + target_ulong msr, *srr_0, *srr_1, *asrr_0, *asrr_1; + int excp, idx; excp = env->exception_index; msr = do_load_msr(env); /* The default is to use SRR0 & SRR1 to save the exception context */ srr_0 = &env->spr[SPR_SRR0]; srr_1 = &env->spr[SPR_SRR1]; + asrr_0 = NULL; + asrr_1 = NULL; #if defined (DEBUG_EXCEPTIONS) if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1) { if (loglevel != 0) { @@ -1397,26 +1400,44 @@ void do_interrupt (CPUState *env) env->nip, excp, env->error_code); } msr_pow = 0; + idx = -1; /* Generate informations in save/restore registers */ switch (excp) { /* Generic PowerPC exceptions */ case EXCP_RESET: /* 0x0100 */ - if (PPC_EXCP(env) != PPC_FLAGS_EXCP_40x) { + switch (PPC_EXCP(env)) { + case PPC_FLAGS_EXCP_40x: + srr_0 = &env->spr[SPR_40x_SRR2]; + srr_1 = &env->spr[SPR_40x_SRR3]; + break; + case PPC_FLAGS_EXCP_BOOKE: + idx = 0; + srr_0 = &env->spr[SPR_BOOKE_CSRR0]; + srr_1 = &env->spr[SPR_BOOKE_CSRR1]; + break; + default: if (msr_ip) excp += 0xFFC00; excp |= 0xFFC00000; - } else { - srr_0 = &env->spr[SPR_40x_SRR2]; - srr_1 = &env->spr[SPR_40x_SRR3]; + break; } goto store_next; case EXCP_MACHINE_CHECK: /* 0x0200 */ - if (msr_me == 0) { - cpu_abort(env, "Machine check exception while not allowed\n"); - } - if (unlikely(PPC_EXCP(env) == PPC_FLAGS_EXCP_40x)) { + switch (PPC_EXCP(env)) { + case PPC_FLAGS_EXCP_40x: srr_0 = &env->spr[SPR_40x_SRR2]; srr_1 = &env->spr[SPR_40x_SRR3]; + break; + case PPC_FLAGS_EXCP_BOOKE: + idx = 1; + srr_0 = &env->spr[SPR_BOOKE_MCSRR0]; + srr_1 = &env->spr[SPR_BOOKE_MCSRR1]; + asrr_0 = &env->spr[SPR_BOOKE_CSRR0]; + asrr_1 = &env->spr[SPR_BOOKE_CSRR1]; + msr_ce = 0; + break; + default: + break; } msr_me = 0; break; @@ -1425,6 +1446,7 @@ void do_interrupt (CPUState *env) /* data location address has been stored * when the fault has been detected */ + idx = 2; msr &= ~0xFFFF0000; #if defined (DEBUG_EXCEPTIONS) if (loglevel) { @@ -1438,6 +1460,7 @@ void do_interrupt (CPUState *env) goto store_next; case EXCP_ISI: /* 0x0400 */ /* Store exception cause */ + idx = 3; msr &= ~0xFFFF0000; msr |= env->error_code; #if defined (DEBUG_EXCEPTIONS) @@ -1448,20 +1471,12 @@ void do_interrupt (CPUState *env) #endif goto store_next; case EXCP_EXTERNAL: /* 0x0500 */ - if (msr_ee == 0) { -#if defined (DEBUG_EXCEPTIONS) - if (loglevel > 0) { - fprintf(logfile, "Skipping hardware interrupt\n"); - } -#endif - /* Requeue it */ - env->interrupt_request |= CPU_INTERRUPT_HARD; - return; - } + idx = 4; goto store_next; case EXCP_ALIGN: /* 0x0600 */ if (likely(PPC_EXCP(env) != PPC_FLAGS_EXCP_601)) { /* Store exception cause */ + idx = 5; /* Get rS/rD and rA from faulting opcode */ env->spr[SPR_DSISR] |= (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16; @@ -1476,6 +1491,7 @@ void do_interrupt (CPUState *env) } goto store_current; case EXCP_PROGRAM: /* 0x0700 */ + idx = 6; msr &= ~0xFFFF0000; switch (env->error_code & ~0xF) { case EXCP_FP: @@ -1501,6 +1517,7 @@ void do_interrupt (CPUState *env) msr |= 0x00040000; break; case EXCP_TRAP: + idx = 15; msr |= 0x00020000; break; default: @@ -1510,18 +1527,13 @@ void do_interrupt (CPUState *env) msr |= 0x00010000; goto store_current; case EXCP_NO_FP: /* 0x0800 */ + idx = 7; msr &= ~0xFFFF0000; goto store_current; case EXCP_DECR: - if (msr_ee == 0) { -#if 1 - /* Requeue it */ - env->interrupt_request |= CPU_INTERRUPT_TIMER; -#endif - return; - } goto store_next; case EXCP_SYSCALL: /* 0x0C00 */ + idx = 8; /* NOTE: this is a temporary hack to support graphics OSI calls from the MOL driver */ if (env->gpr[3] == 0x113724fa && env->gpr[4] == 0x77810f9b && @@ -1557,13 +1569,6 @@ void do_interrupt (CPUState *env) "Instruction segment exception is not implemented yet !\n"); goto store_next; case EXCP_HDECR: /* 0x0980 */ - if (msr_ee == 0) { -#if 1 - /* Requeue it */ - env->interrupt_request |= CPU_INTERRUPT_TIMER; -#endif - return; - } /* XXX: TODO */ cpu_abort(env, "Hypervisor decrementer exception is not implemented " "yet !\n"); @@ -1581,6 +1586,7 @@ void do_interrupt (CPUState *env) } return; case 0x0F20: + idx = 9; switch (PPC_EXCP(env)) { case PPC_FLAGS_EXCP_40x: /* APU unavailable on 405 */ @@ -1600,11 +1606,13 @@ void do_interrupt (CPUState *env) } return; case 0x1000: + idx = 10; switch (PPC_EXCP(env)) { case PPC_FLAGS_EXCP_40x: /* PIT on 4xx */ - /* XXX: TODO */ - cpu_abort(env, "40x PIT exception is not implemented yet !\n"); + msr &= ~0xFFFF0000; + if (loglevel != 0) + fprintf(logfile, "PIT exception\n"); goto store_next; case PPC_FLAGS_EXCP_602: case PPC_FLAGS_EXCP_603: @@ -1619,11 +1627,13 @@ void do_interrupt (CPUState *env) } return; case 0x1010: + idx = 11; switch (PPC_EXCP(env)) { case PPC_FLAGS_EXCP_40x: /* FIT on 4xx */ - /* XXX: TODO */ - cpu_abort(env, "40x FIT exception is not implemented yet !\n"); + msr &= ~0xFFFF0000; + if (loglevel != 0) + fprintf(logfile, "FIT exception\n"); goto store_next; default: cpu_abort(env, "Invalid exception 0x1010 !\n"); @@ -1631,19 +1641,25 @@ void do_interrupt (CPUState *env) } return; case 0x1020: + idx = 12; switch (PPC_EXCP(env)) { case PPC_FLAGS_EXCP_40x: /* Watchdog on 4xx */ - /* XXX: TODO */ - cpu_abort(env, - "40x watchdog exception is not implemented yet !\n"); + msr &= ~0xFFFF0000; + if (loglevel != 0) + fprintf(logfile, "WDT exception\n"); goto store_next; + case PPC_FLAGS_EXCP_BOOKE: + srr_0 = &env->spr[SPR_BOOKE_CSRR0]; + srr_1 = &env->spr[SPR_BOOKE_CSRR1]; + break; default: cpu_abort(env, "Invalid exception 0x1020 !\n"); break; } return; case 0x1100: + idx = 13; switch (PPC_EXCP(env)) { case PPC_FLAGS_EXCP_40x: /* DTLBMISS on 4xx */ @@ -1662,6 +1678,7 @@ void do_interrupt (CPUState *env) } return; case 0x1200: + idx = 14; switch (PPC_EXCP(env)) { case PPC_FLAGS_EXCP_40x: /* ITLBMISS on 4xx */ @@ -1838,6 +1855,10 @@ void do_interrupt (CPUState *env) cpu_abort(env, "601 run mode exception is not implemented yet !\n"); goto store_next; + case PPC_FLAGS_EXCP_BOOKE: + srr_0 = &env->spr[SPR_BOOKE_CSRR0]; + srr_1 = &env->spr[SPR_BOOKE_CSRR1]; + break; default: cpu_abort(env, "Invalid exception 0x1800 !\n"); break; @@ -1852,15 +1873,19 @@ void do_interrupt (CPUState *env) return; store_current: /* save current instruction location */ - *srr_0 = (env->nip - 4) & 0xFFFFFFFFULL; + *srr_0 = env->nip - 4; break; store_next: /* save next instruction location */ - *srr_0 = env->nip & 0xFFFFFFFFULL; + *srr_0 = env->nip; break; } /* Save msr */ *srr_1 = msr; + if (asrr_0 != NULL) + *asrr_0 = *srr_0; + if (asrr_1 != NULL) + *asrr_1 = *srr_1; /* If we disactivated any translation, flush TLBs */ if (msr_ir || msr_dr) { tlb_flush(env, 1); @@ -1877,10 +1902,28 @@ void do_interrupt (CPUState *env) msr_dr = 0; msr_ri = 0; msr_le = msr_ile; - msr_sf = msr_isf; + if (PPC_EXCP(env) == PPC_FLAGS_EXCP_BOOKE) { + msr_cm = msr_icm; + if (idx == -1 || (idx >= 16 && idx < 32)) { + cpu_abort(env, "Invalid exception index for excp %d %08x idx %d\n", + excp, excp, idx); + } +#if defined(TARGET_PPC64) + if (msr_cm) + env->nip = (uint64_t)env->spr[SPR_BOOKE_IVPR]; + else +#endif + env->nip = (uint32_t)env->spr[SPR_BOOKE_IVPR]; + if (idx < 16) + env->nip |= env->spr[SPR_BOOKE_IVOR0 + idx]; + else if (idx < 38) + env->nip |= env->spr[SPR_BOOKE_IVOR32 + idx - 32]; + } else { + msr_sf = msr_isf; + env->nip = excp; + } do_compute_hflags(env); /* Jump to handler */ - env->nip = excp; env->exception_index = EXCP_NONE; } |