1 /*
2  * Copyright (C) 2018-2022 Intel Corporation.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <asm/guest/vm.h>
8 #include <hypercall.h>
9 #include <errno.h>
10 #include <logmsg.h>
11 
12 
13 /**
14  * @brief Switch vCPU state between Normal/Secure World.
15  *
16  * * The hypervisor uses this hypercall to do the world switch
17  * * The hypervisor needs to:
18  *   * save current world vCPU contexts, and load the next world
19  *     vCPU contexts
20  *   * update ``rdi``, ``rsi``, ``rdx``, ``rbx`` to next world
21  *     vCPU contexts
22  *
23  * @param vcpu Pointer to VCPU data structure
24  *
25  * @return 0 on success, non-zero on error.
26  */
hcall_world_switch(struct acrn_vcpu * vcpu,__unused struct acrn_vm * target_vm,__unused uint64_t param1,__unused uint64_t param2)27 int32_t hcall_world_switch(struct acrn_vcpu *vcpu, __unused struct acrn_vm *target_vm,
28 		__unused uint64_t param1, __unused uint64_t param2)
29 {
30 	int32_t next_world_id = !(vcpu->arch.cur_context);
31 	int32_t ret = -EPERM;
32 
33 	if ((vcpu->vm->sworld_control.flag.supported != 0UL) && (next_world_id < NR_WORLD)
34 		&& (vcpu->vm->sworld_control.flag.active != 0UL)) {
35 		switch_world(vcpu, next_world_id);
36 		ret = 0;
37 	}
38 	return ret;
39 }
40 
41 /**
42  * @brief Initialize environment for Trusty-OS on a vCPU.
43  *
44  * * It is used by the User VM OS bootloader (``User VM OS Loader``) to request ACRN
45  *   to initialize Trusty
46  * * The Trusty memory region range, entry point must be specified
47  * * The hypervisor needs to save current vCPU contexts (Normal World)
48  *
49  * @param vcpu Pointer to vCPU data structure
50  * @param param1 guest physical address. This gpa points to trusty_boot_param structure
51  *
52  * @return 0 on success, non-zero on error.
53  */
hcall_initialize_trusty(struct acrn_vcpu * vcpu,__unused struct acrn_vm * target_vm,uint64_t param1,__unused uint64_t param2)54 int32_t hcall_initialize_trusty(struct acrn_vcpu *vcpu, __unused struct acrn_vm *target_vm,
55 		uint64_t param1, __unused uint64_t param2)
56 {
57 	int32_t ret = -EFAULT;
58 
59 	if ((vcpu->vm->sworld_control.flag.supported != 0UL)
60 		&& (vcpu->vm->sworld_control.flag.active == 0UL)
61 		&& (vcpu->arch.cur_context == NORMAL_WORLD)) {
62 		struct trusty_boot_param boot_param;
63 
64 		if (copy_from_gpa(vcpu->vm, &boot_param, param1, sizeof(boot_param)) == 0) {
65 			if (initialize_trusty(vcpu, &boot_param)) {
66 				vcpu->vm->sworld_control.flag.active = 1UL;
67 				ret = 0;
68 			}
69 		}
70 	} else {
71 		ret = -EPERM;
72 		pr_err("%s, context mismatch when initialize trusty.\n", __func__);
73 	}
74 	return ret;
75 }
76 
77 /**
78  * @brief Save/Restore Context of Secure World.
79  *
80  * @param vcpu Pointer to VCPU data structure
81  *
82  * @return 0 on success, non-zero on error.
83  */
hcall_save_restore_sworld_ctx(struct acrn_vcpu * vcpu,__unused struct acrn_vm * target_vm,__unused uint64_t param1,__unused uint64_t param2)84 int32_t hcall_save_restore_sworld_ctx(struct acrn_vcpu *vcpu, __unused struct acrn_vm *target_vm,
85 		__unused uint64_t param1, __unused uint64_t param2)
86 {
87 	struct acrn_vm *vm = vcpu->vm;
88 	int32_t ret = -EINVAL;
89 
90 	if (is_vcpu_bsp(vcpu) && (vm->sworld_control.flag.supported != 0UL)) {
91 		if (vm->sworld_control.flag.active != 0UL) {
92 			save_sworld_context(vcpu);
93 			vm->sworld_control.flag.ctx_saved = 1UL;
94 			ret = 0;
95 		} else {
96 			if (vm->sworld_control.flag.ctx_saved != 0UL) {
97 				restore_sworld_context(vcpu);
98 				vm->sworld_control.flag.ctx_saved = 0UL;
99 				vm->sworld_control.flag.active = 1UL;
100 				ret = 0;
101 			}
102 		}
103 	} else {
104 		ret = -EPERM;
105 		pr_err("%s, states mismatch when save restore sworld context.\n", __func__);
106 	}
107 
108 	return ret;
109 }
110