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 <dongsheng.x.zhang@intel.com>
Acked-by: Eddie Dong <eddie.dong@Intel.com>
This commit is contained in:
dongshen 2021-08-19 15:05:18 -07:00 committed by wenlingz
parent 3ab50f2ef5
commit a7014f4654
3 changed files with 100 additions and 8 deletions

View File

@ -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;
}
/**

View File

@ -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)) {

View File

@ -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_ */