KVM: arm64: Monitor Debug support for non-protected guests Add monitor debug support for non-protected guests in protected mode. Save and restore the monitor debug state when running a non-protected guest, and propagate the monitor debug configuration of non-protected vcpus from the host. This patch assumes that the hyp vcpu debug iflags are kept in sync with the host. Change-Id: I360b968e487b9c4d4345982f10184ea265263ca9 Signed-off-by: Fuad Tabba <tabba@google.com>
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c index 83f35a1..0bcff5d 100644 --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -615,6 +615,57 @@ static void __flush_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu) __copy_vcpu_state(hyp_vcpu->host_vcpu, &hyp_vcpu->vcpu); } +static void flush_debug_state(struct pkvm_hyp_vcpu *hyp_vcpu) +{ + struct kvm_vcpu *vcpu = &hyp_vcpu->vcpu; + struct kvm_vcpu *host_vcpu = hyp_vcpu->host_vcpu; + u64 mdcr_el2 = READ_ONCE(host_vcpu->arch.mdcr_el2); + + /* + * Propagate the monitor debug configuration of the vcpu from host. + * Preserve HPMN, which is set-up by some knowledgeable bootcode. + * Ensure that MDCR_EL2_E2PB_MASK and MDCR_EL2_E2TB_MASK are clear, + * as guests should not be able to access profiling and trace buffers. + * Ensure that RES0 bits are clear. + */ + mdcr_el2 &= ~(MDCR_EL2_RES0 | + MDCR_EL2_HPMN_MASK | + (MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT) | + (MDCR_EL2_E2TB_MASK << MDCR_EL2_E2TB_SHIFT)); + vcpu->arch.mdcr_el2 = read_sysreg(mdcr_el2) & MDCR_EL2_HPMN_MASK; + vcpu->arch.mdcr_el2 |= mdcr_el2; + + vcpu->arch.pmu = host_vcpu->arch.pmu; + vcpu->guest_debug = READ_ONCE(host_vcpu->guest_debug); + + if (!kvm_vcpu_needs_debug_regs(vcpu)) + return; + + __vcpu_save_guest_debug_regs(vcpu); + + /* Switch debug_ptr to the external_debug_state if done by the host. */ + if (kern_hyp_va(READ_ONCE(host_vcpu->arch.debug_ptr)) == + &host_vcpu->arch.external_debug_state) + vcpu->arch.debug_ptr = &host_vcpu->arch.external_debug_state; + + /* Propagate any special handling for single step from host. */ + vcpu_write_sys_reg(vcpu, vcpu_read_sys_reg(host_vcpu, MDSCR_EL1), + MDSCR_EL1); + *vcpu_cpsr(vcpu) = *vcpu_cpsr(host_vcpu); +} + +static void sync_debug_state(struct pkvm_hyp_vcpu *hyp_vcpu) +{ + struct kvm_vcpu *vcpu = &hyp_vcpu->vcpu; + struct kvm_vcpu *host_vcpu = hyp_vcpu->host_vcpu; + + if (!kvm_vcpu_needs_debug_regs(vcpu)) + return; + + __vcpu_restore_guest_debug_regs(vcpu); + vcpu->arch.debug_ptr = &host_vcpu->arch.vcpu_debug_state; +} + static void flush_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu) { struct kvm_vcpu *host_vcpu = hyp_vcpu->host_vcpu; @@ -633,12 +684,11 @@ static void flush_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu) __flush_hyp_vcpu(hyp_vcpu); hyp_vcpu->vcpu.arch.iflags = READ_ONCE(host_vcpu->arch.iflags); + flush_debug_state(hyp_vcpu); + hyp_vcpu->vcpu.arch.hcr_el2 &= ~(HCR_TWI | HCR_TWE); hyp_vcpu->vcpu.arch.hcr_el2 |= READ_ONCE(host_vcpu->arch.hcr_el2) & (HCR_TWI | HCR_TWE); - - hyp_vcpu->vcpu.arch.mdcr_el2 = host_vcpu->arch.mdcr_el2; - hyp_vcpu->vcpu.arch.debug_ptr = kern_hyp_va(host_vcpu->arch.debug_ptr); } hyp_vcpu->vcpu.arch.vsesr_el2 = host_vcpu->arch.vsesr_el2; @@ -677,6 +727,9 @@ static void sync_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu, u32 exit_reason) fpsimd_sve_sync(&hyp_vcpu->vcpu); + if (!pkvm_hyp_vcpu_is_protected(hyp_vcpu)) + sync_debug_state(hyp_vcpu); + /* * Don't sync the vcpu GPR/sysreg state after a run. Instead, * leave it in the hyp vCPU until someone actually requires it.
diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c index e1e782c..e69a548 100644 --- a/arch/arm64/kvm/hyp/nvhe/pkvm.c +++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -644,6 +644,7 @@ static int init_pkvm_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu, hyp_vcpu->vcpu.arch.hw_mmu = &hyp_vm->kvm.arch.mmu; hyp_vcpu->vcpu.arch.cflags = READ_ONCE(host_vcpu->arch.cflags); + hyp_vcpu->vcpu.arch.debug_ptr = &host_vcpu->arch.vcpu_debug_state; ret = pkvm_vcpu_init_sve(hyp_vcpu, host_vcpu); if (ret)