aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Piggin <npiggin@gmail.com>2016-10-27 23:50:58 +1100
committerDavid Gibson <david@gibson.dropbear.id.au>2016-10-28 11:17:35 +1100
commit10c21b5c20bf3d20b7b0ad279db37ae89cc7937d (patch)
tree3656bf0ff51237daf3100b1a42b56b0e88243770
parentcf63246319019c330a214c1ca9284c9405a6eb7a (diff)
ppc: allow certain HV interrupts to be delivered to guests
ppc hypervisors have delivered system reset and machine check exception interrupts to guests in some situations (e.g., see FWNMI feature of LoPAPR, or NMI injection in QEMU). These exceptions are architected to set the HV bit in hardware, however when injected into a guest, the HV bit should be cleared. Current code masks off the HV bit before setting the new MSR, however this happens after the interrupt delivery model has calculated delivery mode for the exception. This can result in the guest's MSR LE bit being lost. Account for this in the exception handler and don't set HV bit for guest delivery. Also add another sanity check to ensure similar bugs get caught. Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
-rw-r--r--target-ppc/excp_helper.c32
1 files changed, 26 insertions, 6 deletions
diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
index 53c407576b..808760bf53 100644
--- a/target-ppc/excp_helper.c
+++ b/target-ppc/excp_helper.c
@@ -213,7 +213,12 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
cs->halted = 1;
cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
}
- new_msr |= (target_ulong)MSR_HVB;
+ if (env->msr_mask & MSR_HVB) {
+ /* ISA specifies HV, but can be delivered to guest with HV clear
+ * (e.g., see FWNMI in PAPR).
+ */
+ new_msr |= (target_ulong)MSR_HVB;
+ }
ail = 0;
/* machine check exceptions don't have ME set */
@@ -391,8 +396,17 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
msr |= 0x10000;
new_msr |= ((target_ulong)1 << MSR_ME);
}
-
- new_msr |= (target_ulong)MSR_HVB;
+ if (env->msr_mask & MSR_HVB) {
+ /* ISA specifies HV, but can be delivered to guest with HV clear
+ * (e.g., see FWNMI in PAPR, NMI injection in QEMU).
+ */
+ new_msr |= (target_ulong)MSR_HVB;
+ } else {
+ if (msr_pow) {
+ cpu_abort(cs, "Trying to deliver power-saving system reset "
+ "exception %d with no HV support\n", excp);
+ }
+ }
ail = 0;
break;
case POWERPC_EXCP_DSEG: /* Data segment exception */
@@ -609,9 +623,15 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
env->spr[srr1] = msr;
/* Sanity check */
- if (!(env->msr_mask & MSR_HVB) && (srr0 == SPR_HSRR0)) {
- cpu_abort(cs, "Trying to deliver HV exception %d with "
- "no HV support\n", excp);
+ if (!(env->msr_mask & MSR_HVB)) {
+ if (new_msr & MSR_HVB) {
+ cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with "
+ "no HV support\n", excp);
+ }
+ if (srr0 == SPR_HSRR0) {
+ cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with "
+ "no HV support\n", excp);
+ }
}
/* If any alternate SRR register are defined, duplicate saved values */