diff --git a/src/core/shim.S b/src/core/shim.S index 6d89038c..4c6a1b86 100644 --- a/src/core/shim.S +++ b/src/core/shim.S @@ -36,7 +36,10 @@ * shim restores X11 from the saved frame before * ERET so the EL0 caller never observes this hint.) * #7 MRS trap (host reads reg from ESR ISS; returns value in x0) - * #9 W^X toggle (x0=FAR, x1=type: 0=exec->RX, 1=write->RW) + * #9 W^X toggle (x0=FAR, x1=type: 0=exec->RX, 1=write->RW. + * On return, X8==0 means retry after W^X TLBI; + * X8==2 means host delivered a signal frame and the + * shim must drop the saved fault frame.) * #10 BRK from EL0 (SIGTRAP delivery / ptrace-stop; GPRs in frame) * #11 EL0 fault (SIGSEGV/SIGILL delivery; GPRs in frame. * On return the host sets X8 to the same TLBI @@ -1119,6 +1122,8 @@ handle_inst_abort: 1: mrs x0, far_el1 /* Faulting address */ mov x1, #0 /* Type 0 = instruction fault -> flip to RX */ hvc #9 + cmp x8, #2 + b.eq exec_drop_frame b tlbi_restore_eret /* handle_data_abort: EC=0x24: Data abort from lower EL @@ -1143,6 +1148,8 @@ handle_data_abort: mrs x0, far_el1 /* Faulting address */ mov x1, #1 /* Type 1 = write fault -> flip to RW */ hvc #9 + cmp x8, #2 + b.eq exec_drop_frame b tlbi_restore_eret /* handle_el0_fault: Deliver SIGSEGV/SIGILL for EL0 faults diff --git a/src/syscall/proc.c b/src/syscall/proc.c index 54a960b9..ac51750b 100644 --- a/src/syscall/proc.c +++ b/src/syscall/proc.c @@ -2065,8 +2065,16 @@ int vcpu_run_loop(hv_vcpu_t vcpu, * so the next syscall epilogue does not re-flush the W^X * page. cpu_tlbi_req is per-vCPU, so this only touches our * own slot -- concurrent vCPUs are unaffected. + * + * The HVC #9 shim now consumes X8 as a post-HVC marker: + * 0 means W^X succeeded and the shim should run the TLBI + * retry epilogue; 2 means signal_deliver_fault installed a + * handler frame and the shim must drop its saved frame. + * Clear X8 here so a guest's pre-fault X8 value cannot be + * misread as the frame-drop marker after a normal toggle. */ tlbi_request_clear(); + hv_vcpu_set_reg(vcpu, HV_REG_X8, 0); break; } diff --git a/src/syscall/signal.c b/src/syscall/signal.c index cb9fa1ca..d6f628a9 100644 --- a/src/syscall/signal.c +++ b/src/syscall/signal.c @@ -1735,9 +1735,11 @@ static int deliver_signal_locked(hv_vcpu_t vcpu, /* If delivery happens while returning from the syscall HVC path, the shim * still has the interrupted syscall frame on its EL1 stack. Tell it to drop * that frame so the handler PC/SP/LR/args installed above are not - * overwritten before ERET. Fault/BRK delivery paths ignore this marker. The - * EL0-preemption path resumes straight into the handler at EL0 with no shim - * frame to drop, so the marker is neither needed nor consulted. + * overwritten before ERET. HVC #9 fault fallback uses the same marker when + * it materializes a SIGSEGV frame; HVC #11 and BRK delivery paths do not + * consume it. The EL0-preemption path resumes straight into the handler at + * EL0 with no shim frame to drop, so the marker is neither needed nor + * consulted. */ if (!el0_preempt) hv_vcpu_set_reg(vcpu, HV_REG_X8, 2);