130 lines
3.5 KiB
C
130 lines
3.5 KiB
C
/*
|
|
* Copyright (C) 2019 Intel Corporation.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include <types.h>
|
|
#include <errno.h>
|
|
#include <asm/cpufeatures.h>
|
|
#include <asm/cpu_caps.h>
|
|
#include <asm/sgx.h>
|
|
#include <asm/cpuid.h>
|
|
#include <asm/guest/vm.h>
|
|
#include <logmsg.h>
|
|
|
|
#define SGX_OPTED_IN (MSR_IA32_FEATURE_CONTROL_SGX_GE | MSR_IA32_FEATURE_CONTROL_LOCK)
|
|
|
|
/* For the static variables, which are not explicitly initialzed will be inited to 0 */
|
|
static int32_t init_sgx_ret = 0;
|
|
static struct epc_section pepc_sections[MAX_EPC_SECTIONS]; /* physcial epc sections */
|
|
static struct epc_map vm_epc_maps[MAX_EPC_SECTIONS][CONFIG_MAX_VM_NUM]; /* epc resource mapping for VMs */
|
|
|
|
static int32_t get_epc_section(uint32_t sec_id, uint64_t* base, uint64_t* size)
|
|
{
|
|
uint32_t eax = 0U, ebx = 0U, ecx = 0U, edx = 0U, type;
|
|
int32_t ret = 0;
|
|
|
|
cpuid_subleaf(CPUID_SGX_LEAF, sec_id + CPUID_SGX_EPC_SUBLEAF_BASE, &eax, &ebx, &ecx, &edx);
|
|
type = eax & CPUID_SGX_EPC_TYPE_MASK;
|
|
if (type == CPUID_SGX_EPC_TYPE_VALID) {
|
|
*base = (((uint64_t)ebx & CPUID_SGX_EPC_HIGH_MASK) << 32U) |
|
|
((uint64_t)eax & CPUID_SGX_EPC_LOW_MASK);
|
|
*size = (((uint64_t)edx & CPUID_SGX_EPC_HIGH_MASK) << 32U) |
|
|
((uint64_t)ecx & CPUID_SGX_EPC_LOW_MASK);
|
|
if (*size != 0UL) {
|
|
pepc_sections[sec_id].base = *base;
|
|
pepc_sections[sec_id].size = *size;
|
|
} else {
|
|
ret = -EINVAL;
|
|
}
|
|
} else if (type == CPUID_SGX_EPC_TYPE_INVALID) {
|
|
/* indicate the end of epc enumeration */
|
|
} else {
|
|
pr_err("%s: unsupport EPC type %u", __func__, type);
|
|
ret = -EINVAL;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Enumerate physcial EPC resource and partition it according to VM configurations.
|
|
* Build the mappings between HPA and GPA for EPT mapping later.
|
|
* EPC resource partition and mapping relationship will stay unchanged after sgx init.
|
|
*/
|
|
static int32_t partition_epc(void)
|
|
{
|
|
uint16_t vm_id = 0U;
|
|
uint32_t psec_id = 0U, mid = 0U;
|
|
uint64_t psec_addr = 0UL, psec_size = 0UL;
|
|
uint64_t vm_request_size = 0UL, free_size = 0UL, alloc_size;
|
|
struct acrn_vm_config *vm_config;
|
|
int32_t ret = 0;
|
|
|
|
while ((psec_id < MAX_EPC_SECTIONS) && (vm_id < CONFIG_MAX_VM_NUM)) {
|
|
if (vm_request_size == 0U) {
|
|
mid = 0U;
|
|
vm_config = get_vm_config(vm_id);
|
|
vm_request_size = vm_config->epc.size;
|
|
}
|
|
if ((free_size == 0UL) && (vm_request_size != 0UL)) {
|
|
ret = get_epc_section(psec_id, &psec_addr, &psec_size);
|
|
free_size = psec_size;
|
|
if ((ret != 0) || (free_size == 0UL)) {
|
|
break;
|
|
}
|
|
psec_id++;
|
|
}
|
|
if (vm_request_size != 0UL) {
|
|
if (vm_request_size <= free_size) {
|
|
alloc_size = vm_request_size;
|
|
} else {
|
|
alloc_size = free_size;
|
|
}
|
|
vm_epc_maps[mid][vm_id].size = alloc_size;
|
|
vm_epc_maps[mid][vm_id].hpa = psec_addr + psec_size - free_size;
|
|
vm_epc_maps[mid][vm_id].gpa = vm_config->epc.base + vm_config->epc.size - vm_request_size;
|
|
vm_request_size -= alloc_size;
|
|
free_size -= alloc_size;
|
|
mid++;
|
|
}
|
|
if (vm_request_size == 0UL) {
|
|
vm_id++;
|
|
}
|
|
}
|
|
if (vm_request_size != 0UL) {
|
|
ret = -ENOMEM;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
struct epc_section* get_phys_epc(void)
|
|
{
|
|
return pepc_sections;
|
|
}
|
|
|
|
struct epc_map* get_epc_mapping(uint16_t vm_id)
|
|
{
|
|
return &vm_epc_maps[0][vm_id];
|
|
}
|
|
|
|
int32_t init_sgx(void)
|
|
{
|
|
if (pcpu_has_cap(X86_FEATURE_SGX)) {
|
|
if ((msr_read(MSR_IA32_FEATURE_CONTROL) & SGX_OPTED_IN) == SGX_OPTED_IN){
|
|
init_sgx_ret = partition_epc();
|
|
if (init_sgx_ret != 0) {
|
|
pr_err("Please change SGX/PRM setting in BIOS or EPC setting in VM config");
|
|
}
|
|
}
|
|
}
|
|
|
|
return init_sgx_ret;
|
|
}
|
|
|
|
bool is_vsgx_supported(uint16_t vm_id)
|
|
{
|
|
return ((init_sgx_ret == 0) && (vm_epc_maps[0][vm_id].size != 0U));
|
|
}
|