hv: vCAT: expose CAT capabilities to vCAT-enabled VM

Expose CAT feature to vCAT VM by reporting the number of
cache ways/CLOSIDs via the 04H/10H cpuid instructions, so that the
VM can take advantage of CAT to prioritize and partition cache
resource for its own tasks.

Add the vcat_pcbm_to_vcbm() function to map pcbm to vcbm

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 13:28:44 -07:00 committed by wenlingz
parent 77ae989379
commit be855d2352
3 changed files with 188 additions and 0 deletions

View File

@ -151,6 +151,22 @@ static uint64_t vcat_get_max_vcbm(const struct acrn_vm *vm, int res)
return max_pcbm >> low;
}
/**
* @brief Map pCBM to vCBM
*
* @pre vm != NULL
*/
uint64_t vcat_pcbm_to_vcbm(const struct acrn_vm *vm, uint64_t pcbm, 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);
/* pcbm set bits should only be in the range of [low, high] */
return (pcbm & max_pcbm) >> low;
}
/**
* @brief vCBM MSR write handler
*

View File

@ -15,6 +15,8 @@
#include <asm/sgx.h>
#include <asm/tsc.h>
#include <logmsg.h>
#include <asm/rdt.h>
#include <asm/guest/vcat.h>
static inline const struct vcpuid_entry *local_find_vcpuid_entry(const struct acrn_vcpu *vcpu,
uint32_t leaf, uint32_t subleaf)
@ -286,6 +288,149 @@ static int32_t set_vcpuid_sgx(struct acrn_vm *vm)
return result;
}
#ifdef CONFIG_VCAT_ENABLED
/**
* @brief * Number of ways (CBM length) is detected with CPUID.0x4
*
* @pre vm != NULL
*/
static int32_t set_vcpuid_vcat_04h(const struct acrn_vm *vm, struct vcpuid_entry *entry)
{
uint32_t cache_type = entry->eax & 0x1FU; /* EAX bits 04:00 */
uint32_t cache_level = (entry->eax >> 5U) & 0x7U; /* EAX bits 07:05 */
uint16_t vcbm_len = 0U;
if (cache_level == 2U) {
vcbm_len = vcat_get_vcbm_len(vm, RDT_RESOURCE_L2);
} else if (cache_level == 3U) {
vcbm_len = vcat_get_vcbm_len(vm, RDT_RESOURCE_L3);
}
/*
* cache_type:
* 0 = Null - No more caches.
* 1 = Data Cache.
* 2 = Instruction Cache.
* 3 = Unified Cache.
* 4-31 = Reserved
*
* cache_level (starts at 1):
* 2 = L2
* 3 = L3
*/
if (((cache_type == 0x1U) || (cache_type == 0x3U)) && (vcbm_len != 0U)) {
/*
* EBX Bits 11 - 00: L = System Coherency Line Size**.
* Bits 21 - 12: P = Physical Line partitions**.
* Bits 31 - 22: W = Ways of associativity**.
*/
entry->ebx &= ~0xFFC00000U;
/* Report # of cache ways (CBM length) to guest VM */
entry->ebx |= (vcbm_len - 1U) << 22U;
}
return 0;
}
/**
* @brief RDT allocation enumeration sub-leaf (EAX = 10H, ECX = 0)
* Expose CAT capabilities to guest VM
*
* @pre vm != NULL
*/
static int32_t set_vcpuid_vcat_10h_subleaf_0(struct acrn_vm *vm, bool l2, bool l3)
{
struct vcpuid_entry entry;
init_vcpuid_entry(CPUID_RDT_ALLOCATION, 0U, CPUID_CHECK_SUBLEAF, &entry);
entry.ebx &= ~0xeU; /* Set the L3/L2/MBA bits (bits 1, 2, and 3) all to 0 (not supported) */
if (l2) {
/* Bit 02: Supports L2 Cache Allocation Technology if 1 */
entry.ebx |= 0x4U;
}
if (l3) {
/* Bit 01: Supports L3 Cache Allocation Technology if 1 */
entry.ebx |= 0x2U;
}
return set_vcpuid_entry(vm, &entry);
}
/**
* @brief L2/L3 enumeration sub-leaf
*
* @pre vm != NULL
*/
static int32_t set_vcpuid_vcat_10h_subleaf_res(struct acrn_vm *vm, uint32_t subleaf, uint16_t num_vclosids)
{
struct vcpuid_entry entry;
uint16_t vcbm_len;
int res;
if (subleaf == 1U) {
res = RDT_RESOURCE_L3;
} else {
res = RDT_RESOURCE_L2;
}
vcbm_len = vcat_get_vcbm_len(vm, res);
/* Set cache cbm_len */
init_vcpuid_entry(CPUID_RDT_ALLOCATION, subleaf, CPUID_CHECK_SUBLEAF, &entry);
if ((entry.eax != 0U) && (vcbm_len != 0U)) {
/* Bits 4 - 00: Length of the capacity bit mask for the corresponding ResID using minus-one notation */
entry.eax = (entry.eax & ~0x1F) | (vcbm_len - 1U);
/* Bits 31 - 00: Bit-granular map of isolation/contention of allocation units
* Each set bit within the length of the CBM indicates the corresponding unit of the L2/L3 allocation
* may be used by other entities in the platform. Each cleared bit within the length of the CBM
* indicates the corresponding allocation unit can be configured to implement a priority-based
* allocation scheme chosen by an OS/VMM without interference with other hardware agents in the system.
*/
entry.ebx = (uint32_t)vcat_pcbm_to_vcbm(vm, entry.ebx, res);
/* Do not support CDP for now */
entry.ecx &= ~0x4U;
/* Report max CLOS to guest VM
* Bits 15 - 00: Highest COS number supported for this ResID using minus-one notation
*/
entry.edx = (entry.edx & 0xFFFF0000U) | (num_vclosids - 1U);
}
return set_vcpuid_entry(vm, &entry);
}
/**
* @pre vm != NULL
*/
static int32_t set_vcpuid_vcat_10h(struct acrn_vm *vm)
{
int32_t result;
uint16_t num_vclosids = vcat_get_num_vclosids(vm);
bool l2 = is_l2_vcat_configured(vm);
bool l3 = is_l3_vcat_configured(vm);
/* RDT allocation enumeration sub-leaf (EAX=10H, ECX=0) */
result = set_vcpuid_vcat_10h_subleaf_0(vm, l2, l3);
if ((result == 0) && l2) {
/* L2 enumeration sub-leaf (EAX=10H, ECX=2) */
result = set_vcpuid_vcat_10h_subleaf_res(vm, 2U, num_vclosids);
}
if ((result == 0) && l3) {
/* L3 enumeration sub-leaf (EAX=10H, ECX=1) */
result = set_vcpuid_vcat_10h_subleaf_res(vm, 1U, num_vclosids);
}
return result;
}
#endif
static int32_t set_vcpuid_extended_function(struct acrn_vm *vm)
{
uint32_t i, limit;
@ -376,6 +521,12 @@ int32_t set_vcpuid_entries(struct acrn_vm *vm)
if (entry.eax == 0U) {
break;
}
#ifdef CONFIG_VCAT_ENABLED
if (is_vcat_configured(vm)) {
result = set_vcpuid_vcat_04h(vm, &entry);
}
#endif
result = set_vcpuid_entry(vm, &entry);
if (result != 0) {
/* wants to break out of switch */
@ -392,6 +543,13 @@ int32_t set_vcpuid_entries(struct acrn_vm *vm)
if (is_vsgx_supported(vm->vm_id)) {
entry.ebx |= CPUID_EBX_SGX;
}
#ifdef CONFIG_VCAT_ENABLED
if (is_vcat_configured(vm)) {
/* Bit 15: Supports Intel Resource Director Technology (Intel RDT) Allocation capability if 1 */
entry.ebx |= CPUID_EBX_PQE;
}
#endif
result = set_vcpuid_entry(vm, &entry);
break;
case 0x12U:
@ -408,7 +566,16 @@ int32_t set_vcpuid_entries(struct acrn_vm *vm)
/* Intel RDT */
case 0x0fU:
break;
/* Intel RDT */
case 0x10U:
#ifdef CONFIG_VCAT_ENABLED
if (is_vcat_configured(vm)) {
result = set_vcpuid_vcat_10h(vm);
}
#endif
break;
/* Intel Processor Trace */
case 0x14U:
/* PCONFIG */

View File

@ -9,7 +9,12 @@
#include <asm/guest/vm.h>
bool is_l2_vcat_configured(const struct acrn_vm *vm);
bool is_l3_vcat_configured(const struct acrn_vm *vm);
uint16_t vcat_get_vcbm_len(const struct acrn_vm *vm, int res);
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);
#endif /* VCAT_H_ */