hv: sgx: add basic support to init sgx resource for vm

Get the platform EPC resource and partiton the EPC resource for VMs
according to VM configurations.
Don't support sgx capability in SOS VM.
init_sgx is called during platform bsp initialization.
If init_sgx() fails, consider it as configuration error, panic the system.
init_sgx() fails if one of the following happens when at least one VM requests
EPC resource if no enough EPC resource for all VMs.
No further check if sgx is not supported by platform or not opted-in in BIOS,
just disable SGX support for VMs.

Tracked-On: #3179
Signed-off-by: Binbin Wu <binbin.wu@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
Binbin Wu 2019-05-22 15:10:41 +08:00 committed by ACRN System Integration
parent c5cfd7c200
commit 245a732055
5 changed files with 228 additions and 0 deletions

View File

@ -215,6 +215,7 @@ C_SRCS += arch/x86/guest/trusty.c
C_SRCS += arch/x86/guest/vm_reset.c
C_SRCS += arch/x86/cat.c
C_SRCS += arch/x86/lib/memory.c
C_SRCS += arch/x86/sgx.c
C_SRCS += lib/string.c
C_SRCS += lib/crypto/crypto_api.c
C_SRCS += lib/crypto/mbedtls/hkdf.c

View File

@ -26,6 +26,7 @@
#include <logmsg.h>
#include <cat.h>
#include <vboot.h>
#include <sgx.h>
#define CPU_UP_TIMEOUT 100U /* millisecond */
#define CPU_DOWN_TIMEOUT 100U /* millisecond */
@ -231,6 +232,10 @@ void init_pcpu_post(uint16_t pcpu_id)
ptdev_init();
if (init_sgx() != 0) {
panic("failed to initialize sgx!");
}
/* Start all secondary cores */
startup_paddr = prepare_trampoline();
if (!start_pcpus(AP_MASK)) {

129
hypervisor/arch/x86/sgx.c Normal file
View File

@ -0,0 +1,129 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <types.h>
#include <errno.h>
#include <cpufeatures.h>
#include <cpu_caps.h>
#include <sgx.h>
#include <cpuid.h>
#include <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));
}

View File

@ -70,6 +70,7 @@
/* Intel-defined CPU features, CPUID level 0x00000007 (EBX)*/
#define X86_FEATURE_TSC_ADJ ((FEAT_7_0_EBX << 5U) + 1U)
#define X86_FEATURE_SGX ((FEAT_7_0_EBX << 5U) + 2U)
#define X86_FEATURE_SMEP ((FEAT_7_0_EBX << 5U) + 7U)
#define X86_FEATURE_ERMS ((FEAT_7_0_EBX << 5U) + 9U)
#define X86_FEATURE_INVPCID ((FEAT_7_0_EBX << 5U) + 10U)

View File

@ -0,0 +1,92 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef SGX_H
#define SGX_H
#define CPUID_SGX_LEAF 0x12U
#define CPUID_SGX_EPC_SUBLEAF_BASE 0x2U
#define CPUID_SGX_EPC_TYPE_MASK 0xFU
#define CPUID_SGX_EPC_TYPE_INVALID 0x0U
#define CPUID_SGX_EPC_TYPE_VALID 0x1U
#define CPUID_SGX_EPC_HIGH_MASK 0x000FFFFFU
#define CPUID_SGX_EPC_LOW_MASK 0xFFFFF000U
#define MAX_EPC_SECTIONS 4U
/**
* @file sgx.h
*
* @brief public APIs for SGX
*/
/**
* @brief SGX
*
* @defgroup acrn_sgx ACRN SGX
* @{
*/
struct epc_section
{
uint64_t base; /* EPC section base, must be page aligned */
uint64_t size; /* EPC section size in byte, must be page aligned */
};
struct epc_map
{
uint64_t hpa; /* EPC reource address in host, must be page aligned */
uint64_t gpa; /* EPC reource address in guest, must be page aligned */
uint64_t size; /* EPC reource size in byte, must be page aligned */
};
/**
* @brief Get physcial EPC sections of the platform.
*
* @retval Physical EPC sections of the platform
*
*/
struct epc_section* get_phys_epc(void);
/**
* @brief Get EPC resource information for a specific VM.
*
* @param[in] vm_id VM ID to specify a VM
*
* @retval EPC sections for a VM
*
* @pre vm_id < CONFIG_MAX_VM_NUM
*
*/
struct epc_map* get_epc_mapping(uint16_t vm_id);
/**
* @brief If SGX support is enabled or not for a specific VM.
*
* @param[in] vm_id VM ID to specify a VM
*
* @retval True when SGX is supported in the specific VM
* @retval False When SGX is not supported in the specific VM
*
* @pre vm_id < CONFIG_MAX_VM_NUM
*
*/
bool is_vsgx_supported(uint16_t vm_id);
/**
* @brief SGX initialization.
*
* Init SGX and parition EPC resource for VMs.
*
* @retval 0 on success
* @retval <0 on failure
*
*/
int32_t init_sgx(void);
/**
* @}
*/
#endif