From 3c9c41b65681e6b3ef7242c9a0e1ad934d12afb3 Mon Sep 17 00:00:00 2001 From: Jie Deng Date: Fri, 12 Nov 2021 15:13:08 +0800 Subject: [PATCH] hv: tee: add x86_tee hypercall interfaces This patch adds the x86_tee hypercall interfaces. - HC_TEE_VCPU_BOOT_DONE This hypercall is used to notify the hypervisor that the TEE VCPU Boot is done, so that we can sleep the corresponding TEE VCPU. REE will be started at the last time this hypercall is called by TEE. - HC_SWITCH_EE For REE VM, it uses this hypercall to request TEE service. For TEE VM, it uses this hypercall to switch back to REE when it completes the REE service. Tracked-On: #6571 Signed-off-by: Jie Deng Reviewed-by: Wang, Yu1 Acked-by: Eddie Dong --- hypervisor/arch/x86/guest/optee.c | 13 ++++++++ hypervisor/arch/x86/guest/vm.c | 39 +++++++++++++++------- hypervisor/arch/x86/guest/vmcall.c | 23 +++++++++++-- hypervisor/include/arch/x86/asm/guest/vm.h | 2 +- hypervisor/include/common/hypercall.h | 26 +++++++++++++++ hypervisor/include/public/acrn_hv_defs.h | 5 +++ 6 files changed, 92 insertions(+), 16 deletions(-) diff --git a/hypervisor/arch/x86/guest/optee.c b/hypervisor/arch/x86/guest/optee.c index ad6069551..6263a0c3c 100644 --- a/hypervisor/arch/x86/guest/optee.c +++ b/hypervisor/arch/x86/guest/optee.c @@ -11,6 +11,7 @@ #include #include #include +#include void prepare_tee_vm_memmap(struct acrn_vm *vm, const struct acrn_vm_config *vm_config) { @@ -33,3 +34,15 @@ void prepare_tee_vm_memmap(struct acrn_vm *vm, const struct acrn_vm_config *vm_c ept_del_mr(vm, (uint64_t *)vm->arch_vm.nworld_eptp, hv_hpa, get_hv_ram_size()); } } + +int32_t hcall_handle_tee_vcpu_boot_done(struct acrn_vcpu *vcpu, __unused struct acrn_vm *target_vm, + __unused uint64_t param1, __unused uint64_t param2) +{ + return 0; +} + +int32_t hcall_switch_ee(struct acrn_vcpu *vcpu, __unused struct acrn_vm *target_vm, + __unused uint64_t param1, __unused uint64_t param2) +{ + return 0; +} diff --git a/hypervisor/arch/x86/guest/vm.c b/hypervisor/arch/x86/guest/vm.c index 655a7d303..bb5b99288 100644 --- a/hypervisor/arch/x86/guest/vm.c +++ b/hypervisor/arch/x86/guest/vm.c @@ -978,7 +978,7 @@ static uint8_t loaded_pre_vm_nr = 0U; * * @pre vm_id < CONFIG_MAX_VM_NUM && vm_config != NULL */ -void prepare_vm(uint16_t vm_id, struct acrn_vm_config *vm_config) +int32_t prepare_vm(uint16_t vm_id, struct acrn_vm_config *vm_config) { int32_t err = 0; struct acrn_vm *vm = NULL; @@ -1024,17 +1024,9 @@ void prepare_vm(uint16_t vm_id, struct acrn_vm_config *vm_config) if (is_prelaunched_vm(vm)) { loaded_pre_vm_nr++; } - - if (err == 0) { - - /* start vm BSP automatically */ - start_vm(vm); - - pr_acrnlog("Start VM id: %x name: %s", vm_id, vm_config->name); - } else { - pr_err("Failed to load VM id: %x name: %s, error = %d", vm_id, vm_config->name, err); - } } + + return err; } /** @@ -1048,12 +1040,35 @@ void launch_vms(uint16_t pcpu_id) for (vm_id = 0U; vm_id < CONFIG_MAX_VM_NUM; vm_id++) { vm_config = get_vm_config(vm_id); + + if ((vm_config->guest_flags & GUEST_FLAG_REE) != 0U && + (vm_config->guest_flags & GUEST_FLAG_TEE) != 0U) { + ASSERT(false, "%s: Wrong VM (VM id: %u) configuration, can't set both REE and TEE flags", + __func__, vm_id); + } + if ((vm_config->load_order == SERVICE_VM) || (vm_config->load_order == PRE_LAUNCHED_VM)) { if (pcpu_id == get_configured_bsp_pcpu_id(vm_config)) { if (vm_config->load_order == SERVICE_VM) { service_vm_ptr = &vm_array[vm_id]; } - prepare_vm(vm_id, vm_config); + + /* + * We can only start a VM when there is no error in prepare_vm. + * Otherwise, print out the corresponding error. + * + * We can only start REE VM when get the notification from TEE VM. + * so skip "start_vm" here for REE, and start it in TEE hypercall + * HC_TEE_VCPU_BOOT_DONE. + */ + if (prepare_vm(vm_id, vm_config) == 0) { + if ((vm_config->guest_flags & GUEST_FLAG_REE) != 0U) { + /* Nothing need to do here, REE will start in TEE hypercall */ + } else { + start_vm(get_vm_from_vmid(vm_id)); + pr_acrnlog("Start VM id: %x name: %s", vm_id, vm_config->name); + } + } } } } diff --git a/hypervisor/arch/x86/guest/vmcall.c b/hypervisor/arch/x86/guest/vmcall.c index 688c69f93..76a162433 100644 --- a/hypervisor/arch/x86/guest/vmcall.c +++ b/hypervisor/arch/x86/guest/vmcall.c @@ -104,6 +104,12 @@ static const struct hc_dispatch hc_dispatch_table[] = { [HC_IDX(HC_SAVE_RESTORE_SWORLD_CTX)] = { .handler = hcall_save_restore_sworld_ctx, .permission_flags = GUEST_FLAG_SECURE_WORLD_ENABLED}, + [HC_IDX(HC_TEE_VCPU_BOOT_DONE)] = { + .handler = hcall_handle_tee_vcpu_boot_done, + .permission_flags = GUEST_FLAG_TEE}, + [HC_IDX(HC_SWITCH_EE)] = { + .handler = hcall_switch_ee, + .permission_flags = (GUEST_FLAG_TEE | GUEST_FLAG_REE)}, }; uint16_t allocate_dynamical_vmid(struct acrn_vm_creation *cv) @@ -123,6 +129,18 @@ uint16_t allocate_dynamical_vmid(struct acrn_vm_creation *cv) } #define GUEST_FLAGS_ALLOWING_HYPERCALLS GUEST_FLAG_SECURE_WORLD_ENABLED +static bool is_guest_hypercall(struct acrn_vm *vm) +{ + uint64_t guest_flags = get_vm_config(vm->vm_id)->guest_flags; + bool ret = true; + + if ((guest_flags & (GUEST_FLAG_SECURE_WORLD_ENABLED | + GUEST_FLAG_TEE | GUEST_FLAG_REE)) == 0UL) { + ret = false; + } + + return ret; +} struct acrn_vm *parse_target_vm(struct acrn_vm *service_vm, uint64_t hcall_id, uint64_t param1, __unused uint64_t param2) { @@ -214,7 +232,7 @@ static int32_t dispatch_hypercall(struct acrn_vcpu *vcpu) put_vm_lock(target_vm); } } else if ((permission_flags != 0UL) && - ((guest_flags & permission_flags) == permission_flags)) { + ((guest_flags & permission_flags) != 0UL)) { ret = dispatch->handler(vcpu, vcpu->vm, param1, param2); } else { /* The vCPU is not allowed to invoke the given hypercall. Keep `ret` as -EINVAL and no @@ -238,7 +256,6 @@ int32_t vmcall_vmexit_handler(struct acrn_vcpu *vcpu) struct acrn_vm *vm = vcpu->vm; /* hypercall ID from guest*/ uint64_t hypcall_id = vcpu_get_gpreg(vcpu, CPU_REG_R8); - uint64_t guest_flags = get_vm_config(vm->vm_id)->guest_flags; /* * The following permission checks are applied to hypercalls. @@ -251,7 +268,7 @@ int32_t vmcall_vmexit_handler(struct acrn_vcpu *vcpu) * guest flags. Attempts to invoke an unpermitted hypercall will make a vCPU see -EINVAL as the return * value. No exception is triggered in this case. */ - if (!is_service_vm(vm) && ((guest_flags & GUEST_FLAGS_ALLOWING_HYPERCALLS) == 0UL)) { + if (!is_service_vm(vm) && !is_guest_hypercall(vm)) { vcpu_inject_ud(vcpu); ret = -ENODEV; } else if (!is_hypercall_from_ring0()) { diff --git a/hypervisor/include/arch/x86/asm/guest/vm.h b/hypervisor/include/arch/x86/asm/guest/vm.h index a4d510893..b01bfac8e 100644 --- a/hypervisor/include/arch/x86/asm/guest/vm.h +++ b/hypervisor/include/arch/x86/asm/guest/vm.h @@ -233,7 +233,7 @@ void resume_vm_from_s3(struct acrn_vm *vm, uint32_t wakeup_vec); void start_vm(struct acrn_vm *vm); int32_t reset_vm(struct acrn_vm *vm); int32_t create_vm(uint16_t vm_id, uint64_t pcpu_bitmap, struct acrn_vm_config *vm_config, struct acrn_vm **rtn_vm); -void prepare_vm(uint16_t vm_id, struct acrn_vm_config *vm_config); +int32_t prepare_vm(uint16_t vm_id, struct acrn_vm_config *vm_config); void launch_vms(uint16_t pcpu_id); bool is_poweroff_vm(const struct acrn_vm *vm); bool is_created_vm(const struct acrn_vm *vm); diff --git a/hypervisor/include/common/hypercall.h b/hypervisor/include/common/hypercall.h index d81d40f07..27563ab80 100644 --- a/hypervisor/include/common/hypercall.h +++ b/hypervisor/include/common/hypercall.h @@ -477,6 +477,32 @@ int32_t hcall_initialize_trusty(struct acrn_vcpu *vcpu, struct acrn_vm *target_v int32_t hcall_save_restore_sworld_ctx(struct acrn_vcpu *vcpu, struct acrn_vm *target_vm, uint64_t param1, uint64_t param2); +/** + * @brief Handle the TEE boot done signal. + * + * @param vcpu Pointer to VCPU data structure + * @param target_vm not used + * @param param1 not used + * @param param2 not used + * + * @return 0 on success, non-zero on error. + */ +int32_t hcall_handle_tee_vcpu_boot_done(struct acrn_vcpu *vcpu, struct acrn_vm *target_vm, + uint64_t param1, uint64_t param2); + +/** + * @brief Switch the execution environment. + * + * @param vcpu Pointer to VCPU data structure + * @param target_vm not used + * @param param1 not used + * @param param2 not used + * + * @return 0 on success, non-zero on error. + */ +int32_t hcall_switch_ee(struct acrn_vcpu *vcpu, struct acrn_vm *target_vm, + uint64_t param1, uint64_t param2); + /** * @} */ diff --git a/hypervisor/include/public/acrn_hv_defs.h b/hypervisor/include/public/acrn_hv_defs.h index d8a1136d7..4428e31a7 100644 --- a/hypervisor/include/public/acrn_hv_defs.h +++ b/hypervisor/include/public/acrn_hv_defs.h @@ -89,6 +89,11 @@ #define HC_ID_PM_BASE 0x80UL #define HC_PM_GET_CPU_STATE BASE_HC_ID(HC_ID, HC_ID_PM_BASE + 0x00UL) +/* X86 TEE */ +#define HC_ID_TEE_BASE 0x90UL +#define HC_TEE_VCPU_BOOT_DONE BASE_HC_ID(HC_ID, HC_ID_TEE_BASE + 0x00UL) +#define HC_SWITCH_EE BASE_HC_ID(HC_ID, HC_ID_TEE_BASE + 0x01UL) + #define ACRN_INVALID_VMID (0xffffU) #define ACRN_INVALID_HPA (~0UL)