| // SPDX-License-Identifier: GPL-2.0 |
| /* |
| * Copyright (c) 2026 Qualcomm Technologies, Inc. |
| */ |
| |
| #include <linux/kvm_host.h> |
| #include <asm/kvm_nacl.h> |
| |
| #define KVM_HEDELEG_DEFAULT (BIT(EXC_INST_MISALIGNED) | \ |
| BIT(EXC_INST_ILLEGAL) | \ |
| BIT(EXC_BREAKPOINT) | \ |
| BIT(EXC_SYSCALL) | \ |
| BIT(EXC_INST_PAGE_FAULT) | \ |
| BIT(EXC_LOAD_PAGE_FAULT) | \ |
| BIT(EXC_STORE_PAGE_FAULT)) |
| |
| #define KVM_HIDELEG_DEFAULT (BIT(IRQ_VS_SOFT) | \ |
| BIT(IRQ_VS_TIMER) | \ |
| BIT(IRQ_VS_EXT)) |
| |
| void kvm_riscv_vcpu_config_init(struct kvm_vcpu *vcpu) |
| { |
| vcpu->arch.cfg.hedeleg = KVM_HEDELEG_DEFAULT; |
| vcpu->arch.cfg.hideleg = KVM_HIDELEG_DEFAULT; |
| } |
| |
| void kvm_riscv_vcpu_config_guest_debug(struct kvm_vcpu *vcpu) |
| { |
| struct kvm_vcpu_config *cfg = &vcpu->arch.cfg; |
| |
| if (vcpu->guest_debug) |
| cfg->hedeleg &= ~BIT(EXC_BREAKPOINT); |
| else |
| cfg->hedeleg |= BIT(EXC_BREAKPOINT); |
| |
| vcpu->arch.csr_dirty = true; |
| } |
| |
| void kvm_riscv_vcpu_config_ran_once(struct kvm_vcpu *vcpu) |
| { |
| const unsigned long *isa = vcpu->arch.isa; |
| struct kvm_vcpu_config *cfg = &vcpu->arch.cfg; |
| |
| if (riscv_isa_extension_available(isa, SVPBMT)) |
| cfg->henvcfg |= ENVCFG_PBMTE; |
| |
| if (riscv_isa_extension_available(isa, SSTC)) |
| cfg->henvcfg |= ENVCFG_STCE; |
| |
| if (riscv_isa_extension_available(isa, ZICBOM)) |
| cfg->henvcfg |= (ENVCFG_CBIE | ENVCFG_CBCFE); |
| |
| if (riscv_isa_extension_available(isa, ZICBOZ)) |
| cfg->henvcfg |= ENVCFG_CBZE; |
| |
| if (riscv_isa_extension_available(isa, SVADU) && |
| !riscv_isa_extension_available(isa, SVADE)) |
| cfg->henvcfg |= ENVCFG_ADUE; |
| |
| if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN)) { |
| cfg->hstateen0 |= SMSTATEEN0_HSENVCFG; |
| if (riscv_isa_extension_available(isa, SSAIA)) |
| cfg->hstateen0 |= SMSTATEEN0_AIA_IMSIC | |
| SMSTATEEN0_AIA | |
| SMSTATEEN0_AIA_ISEL; |
| if (riscv_isa_extension_available(isa, SMSTATEEN)) |
| cfg->hstateen0 |= SMSTATEEN0_SSTATEEN0; |
| } |
| |
| if (vcpu->guest_debug) |
| cfg->hedeleg &= ~BIT(EXC_BREAKPOINT); |
| } |
| |
| void kvm_riscv_vcpu_config_load(struct kvm_vcpu *vcpu) |
| { |
| struct kvm_vcpu_config *cfg = &vcpu->arch.cfg; |
| void *nsh; |
| |
| if (kvm_riscv_nacl_sync_csr_available()) { |
| nsh = nacl_shmem(); |
| nacl_csr_write(nsh, CSR_HEDELEG, cfg->hedeleg); |
| nacl_csr_write(nsh, CSR_HIDELEG, cfg->hideleg); |
| nacl_csr_write(nsh, CSR_HENVCFG, cfg->henvcfg); |
| if (IS_ENABLED(CONFIG_32BIT)) |
| nacl_csr_write(nsh, CSR_HENVCFGH, cfg->henvcfg >> 32); |
| if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN)) { |
| nacl_csr_write(nsh, CSR_HSTATEEN0, cfg->hstateen0); |
| if (IS_ENABLED(CONFIG_32BIT)) |
| nacl_csr_write(nsh, CSR_HSTATEEN0H, cfg->hstateen0 >> 32); |
| } |
| } else { |
| csr_write(CSR_HEDELEG, cfg->hedeleg); |
| csr_write(CSR_HIDELEG, cfg->hideleg); |
| csr_write(CSR_HENVCFG, cfg->henvcfg); |
| if (IS_ENABLED(CONFIG_32BIT)) |
| csr_write(CSR_HENVCFGH, cfg->henvcfg >> 32); |
| if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN)) { |
| csr_write(CSR_HSTATEEN0, cfg->hstateen0); |
| if (IS_ENABLED(CONFIG_32BIT)) |
| csr_write(CSR_HSTATEEN0H, cfg->hstateen0 >> 32); |
| } |
| } |
| } |