diff --git a/hypervisor/Makefile b/hypervisor/Makefile index aebb8a06a..9d4a1ee0d 100644 --- a/hypervisor/Makefile +++ b/hypervisor/Makefile @@ -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 diff --git a/hypervisor/arch/x86/cpu.c b/hypervisor/arch/x86/cpu.c index ee9f70e53..c80fdc094 100644 --- a/hypervisor/arch/x86/cpu.c +++ b/hypervisor/arch/x86/cpu.c @@ -26,6 +26,7 @@ #include #include #include +#include #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)) { diff --git a/hypervisor/arch/x86/sgx.c b/hypervisor/arch/x86/sgx.c new file mode 100644 index 000000000..0ff324c57 --- /dev/null +++ b/hypervisor/arch/x86/sgx.c @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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)); +} diff --git a/hypervisor/include/arch/x86/cpufeatures.h b/hypervisor/include/arch/x86/cpufeatures.h index af41ba766..b49205221 100644 --- a/hypervisor/include/arch/x86/cpufeatures.h +++ b/hypervisor/include/arch/x86/cpufeatures.h @@ -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) diff --git a/hypervisor/include/arch/x86/sgx.h b/hypervisor/include/arch/x86/sgx.h new file mode 100644 index 000000000..1b336d1a0 --- /dev/null +++ b/hypervisor/include/arch/x86/sgx.h @@ -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