From a7014f46545c2740f5df822153554d6381e05171 Mon Sep 17 00:00:00 2001 From: dongshen Date: Thu, 19 Aug 2021 15:05:18 -0700 Subject: [PATCH] hv: vCAT: implementing the vCAT MSRs write handler Implement the write_vcbm() function to handle the MSR_IA32_type_MASK_n vCBM MSRs write request Call write_vclosid() to handle MSR_IA32_PQR_ASSOC MSR write request Several vCAT P2V (physical to virtual) and V2P (virtual to physical) mappings exist: struct acrn_vm_config *vm_config = get_vm_config(vm_id) max_pcbm = vm_config->max_type_pcbm (type: l2 or l3) mask_shift = ffs64(max_pcbm) vclosid = vmsr - MSR_IA32_type_MASK_0 pclosid = vm_config->pclosids[vclosid] pmsr = MSR_IA32_type_MASK_0 + pclosid pcbm = vcbm << mask_shift vcbm = pcbm >> mask_shift Where MSR_IA32_type_MASK_n: L2 or L3 mask msr address for CLOSIDn, from 0C90H through 0D8FH (inclusive). max_pcbm: a bitmask that selects all the physical cache ways assigned to the VM vclosid: virtual CLOSID, always starts from 0 pclosid: corresponding physical CLOSID for a given vclosid vmsr: virtual msr address, passed to vCAT handlers by the caller functions rdmsr_vmexit_handler()/wrmsr_vmexit_handler() pmsr: physical msr address vcbm: virtual CBM, passed to vCAT handlers by the caller functions rdmsr_vmexit_handler()/wrmsr_vmexit_handler() pcbm: physical CBM Tracked-On: #5917 Signed-off-by: dongshen Acked-by: Eddie Dong --- hypervisor/arch/x86/guest/vcat.c | 93 ++++++++++++++++++-- hypervisor/arch/x86/guest/vmsr.c | 13 +++ hypervisor/include/arch/x86/asm/guest/vcat.h | 2 + 3 files changed, 100 insertions(+), 8 deletions(-) diff --git a/hypervisor/arch/x86/guest/vcat.c b/hypervisor/arch/x86/guest/vcat.c index fdfc5551c..b760fd2a4 100644 --- a/hypervisor/arch/x86/guest/vcat.c +++ b/hypervisor/arch/x86/guest/vcat.c @@ -209,20 +209,97 @@ int32_t read_vcbm(const struct acrn_vcpu *vcpu, uint32_t vmsr, uint64_t *rval) return ret; } +/** + * @brief Map vCBM to pCBM + * + * @pre vm != NULL && ((vcbm & vcat_get_max_vcbm(vm, res)) == vcbm) + */ +static uint64_t vcbm_to_pcbm(const struct acrn_vm *vm, uint64_t vcbm, int res) +{ + uint64_t max_pcbm = get_max_pcbm(vm, res); + + /* Find the position low (the first bit set) in max_pcbm */ + uint16_t low = ffs64(max_pcbm); + + return vcbm << low; +} + +/* + * Check if bitmask is contiguous: + * All (and only) contiguous '1' combinations are allowed (e.g. FFFFH, 0FF0H, 003CH, etc.) + */ +static bool is_contiguous(uint64_t bitmask) +{ + bool ret = false; + + if (bitmask != 0UL) { + uint16_t low = ffs64(bitmask); + uint16_t high = fls64(bitmask); + + if (((2UL << high) - (1UL << low)) == bitmask) { + ret = true; + } + } + + return ret; +} + /** * @brief vCBM MSR write handler * * @pre vcpu != NULL && vcpu->vm != NULL */ -int32_t write_vcbm(__unused struct acrn_vcpu *vcpu, __unused uint32_t vmsr, __unused uint64_t val) +int32_t write_vcbm(struct acrn_vcpu *vcpu, uint32_t vmsr, uint64_t val) { - /* - * TODO: this is going to be implemented in a subsequent commit, will perform the following actions: - * write vCBM - * vmsr to pmsr and vcbm to pcbm - * write pCBM - */ - return -EACCES; + int ret = -EACCES; + struct acrn_vm *vm = vcpu->vm; + int res = -1; + uint32_t msr_base; + + if (is_vcat_configured(vm)) { + if (is_l2_vcbm_msr(vm, vmsr)) { + res = RDT_RESOURCE_L2; + msr_base = MSR_IA32_L2_MASK_BASE; + } else if (is_l3_vcbm_msr(vm, vmsr)) { + res = RDT_RESOURCE_L3; + msr_base = MSR_IA32_L3_MASK_BASE; + } + } + + if (res >= 0) { + /* + * vcbm set bits should only be in the range of [0, vcbm_len) (vcat_get_max_vcbm), + * so mask with vcat_get_max_vcbm to prevent erroneous vCBM value + */ + uint64_t masked_vcbm = val & vcat_get_max_vcbm(vm, res); + + /* + * Validity check on val: + * Bits 63:32 of val are reserved and must be written with zeros + * (satisfied by the masked_vcbm == val condition) + * vCBM must be contiguous + */ + if ((masked_vcbm == val) && is_contiguous(val)) { + uint32_t pmsr; + uint16_t vclosid; + uint64_t pcbm, pvalue; + + /* Write vCBM first: */ + vcpu_set_guest_msr(vcpu, vmsr, val); + + /* Write pCBM: */ + vclosid = (uint16_t)(vmsr - msr_base); + pmsr = msr_base + (uint32_t)vclosid_to_pclosid(vm, vclosid); + pcbm = vcbm_to_pcbm(vm, val, res); + /* Preserve reserved bits, and only set the pCBM bits */ + pvalue = (msr_read(pmsr) & ~get_max_pcbm(vm, res)) | pcbm; + msr_write(pmsr, pvalue); + + ret = 0; + } + } + + return ret; } /** diff --git a/hypervisor/arch/x86/guest/vmsr.c b/hypervisor/arch/x86/guest/vmsr.c index 5df1b4612..9843a8fea 100644 --- a/hypervisor/arch/x86/guest/vmsr.c +++ b/hypervisor/arch/x86/guest/vmsr.c @@ -1098,6 +1098,19 @@ int32_t wrmsr_vmexit_handler(struct acrn_vcpu *vcpu) } break; } +#ifdef CONFIG_VCAT_ENABLED + case MSR_IA32_L2_MASK_BASE ... (MSR_IA32_L2_MASK_BASE + NUM_VCAT_L2_MSRS - 1U): + case MSR_IA32_L3_MASK_BASE ... (MSR_IA32_L3_MASK_BASE + NUM_VCAT_L3_MSRS - 1U): + { + err = write_vcbm(vcpu, msr, v); + break; + } + case MSR_IA32_PQR_ASSOC: + { + err = write_vclosid(vcpu, v); + break; + } +#endif default: { if (is_x2apic_msr(msr)) { diff --git a/hypervisor/include/arch/x86/asm/guest/vcat.h b/hypervisor/include/arch/x86/asm/guest/vcat.h index af764435a..f400b7529 100644 --- a/hypervisor/include/arch/x86/asm/guest/vcat.h +++ b/hypervisor/include/arch/x86/asm/guest/vcat.h @@ -16,7 +16,9 @@ void init_vcat_msrs(struct acrn_vcpu *vcpu); uint16_t vcat_get_num_vclosids(const struct acrn_vm *vm); uint64_t vcat_pcbm_to_vcbm(const struct acrn_vm *vm, uint64_t pcbm, int res); int32_t read_vcbm(const struct acrn_vcpu *vcpu, uint32_t vmsr, uint64_t *rval); +int32_t write_vcbm(struct acrn_vcpu *vcpu, uint32_t vmsr, uint64_t val); int32_t read_vclosid(const struct acrn_vcpu *vcpu, uint64_t *rval); +int32_t write_vclosid(struct acrn_vcpu *vcpu, uint64_t val); #endif /* VCAT_H_ */