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)