mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-21 13:08:42 +00:00
trusty: implement hypercall to initialize trusty
UOS_Loader will trigger boot of Trusty-OS by HC_INITIALIZE_TRUSTY. UOS_Loader will load trusty image and alloc runtime memory for trusty. UOS_Loader will transfer these information include trusty runtime memory base address, entry address and memory size to hypervisor by trusty_boot_param structure. In hypervisor, once HC_INITIALIZE_TRUSTY received, it will create EPT for Secure World, save Normal World vCPU context, init Secure World vCPU context and switch World state to Secure World. Signed-off-by: Qi Yadong <yadong.qi@intel.com>
This commit is contained in:
parent
74929d7fe5
commit
c4254179bc
@ -49,8 +49,8 @@ Note: Trusty OS is running in Secure World in the architecture above.
|
||||
**************************
|
||||
Trusty specific Hypercalls
|
||||
**************************
|
||||
1. HC_LAUNCH_TRUSTY
|
||||
->This Hypercall is used by UOSloader (User OS Bootloader) to request ACRN to launch Trusty.
|
||||
1. HC_INITIALIZE_TRUSTY
|
||||
->This Hypercall is used by UOS_Loader to request ACRN to initialize Trusty.
|
||||
->The Trusty memory region range, entry point must be specified.
|
||||
->Hypervisor needs to save current vCPU contexts (Normal World).
|
||||
2. HC_WORLD_SWITCH
|
||||
@ -60,7 +60,7 @@ Trusty specific Hypercalls
|
||||
|
||||
API
|
||||
---
|
||||
1. hcall_launch_trusty(vm_t *vm);
|
||||
1. hcall_initialize_trusty(vm_t *vm);
|
||||
2. hcall_world_switch(vm_t *vm);
|
||||
|
||||
|
||||
@ -71,12 +71,12 @@ Per design, UOSloader will trigger boot of Trusty. So the boot flow will be:
|
||||
UOSloader --> ACRN --> Trusty --> ACRN --> UOSloader
|
||||
|
||||
Detail:
|
||||
1. UOSloader
|
||||
1. UOS_Loader
|
||||
1.1 load and verify trusty image from virtual disk.
|
||||
1.2 allocate runtime memory for trusty.
|
||||
1.3 do ELF relocation of trusty image and get entry address.
|
||||
1.4 call HC_LAUNCH_TRUSTY with trusty memory base and entry address.
|
||||
2. ACRN(HC_LAUNCH_TRUSTY)
|
||||
1.4 call HC_INITIALIZE_TRUSTY with trusty memory base and entry address.
|
||||
2. ACRN(HC_INITIALIZE_TRUSTY)
|
||||
2.1 save World context for Normal World.
|
||||
2.2 init World context for Secure World(RIP, RSP, EPT, etc.).
|
||||
2.3 resume to Secure World.
|
||||
@ -85,9 +85,9 @@ Detail:
|
||||
3.2 call HC_WORLD_SWITCH to switch back to Normal World if boot completed.
|
||||
4. ACRN(HC_WORLD_SWITCH)
|
||||
4.1 save World context for the World which caused this vmexit(Secure World)
|
||||
4.2 restore World context for next World(Normal World(UOSloader))
|
||||
4.3 resume to next World(UOSloader)
|
||||
5. UOSloader
|
||||
4.2 restore World context for next World(Normal World(UOS_Loader))
|
||||
4.3 resume to next World(UOS_Loader)
|
||||
5. UOS_Loader
|
||||
5.1 continue to boot.
|
||||
|
||||
|
||||
|
@ -138,6 +138,10 @@ int vmcall_handler(struct vcpu *vcpu)
|
||||
ret = hcall_world_switch(vcpu);
|
||||
break;
|
||||
|
||||
case HC_INITIALIZE_TRUSTY:
|
||||
ret = hcall_initialize_trusty(vcpu, param1);
|
||||
break;
|
||||
|
||||
default:
|
||||
pr_err("op %d: Invalid hypercall\n", hypcall_id);
|
||||
ret = -1;
|
||||
|
@ -39,6 +39,38 @@ _Static_assert(NR_WORLD == 2, "Only 2 Worlds supported!");
|
||||
/* Trusty EPT rebase gpa: 511G */
|
||||
#define TRUSTY_EPT_REBASE_GPA (511ULL*1024ULL*1024ULL*1024ULL)
|
||||
|
||||
#define TRUSTY_VERSION 1
|
||||
|
||||
struct trusty_startup_param {
|
||||
uint32_t size_of_this_struct;
|
||||
uint32_t mem_size;
|
||||
uint64_t tsc_per_ms;
|
||||
uint64_t trusty_mem_base;
|
||||
uint32_t reserved;
|
||||
uint8_t padding[4];
|
||||
};
|
||||
|
||||
struct trusty_mem {
|
||||
/* The first page of trusty memory is reserved for key_info and
|
||||
* trusty_startup_param.
|
||||
*/
|
||||
union {
|
||||
struct {
|
||||
struct key_info key_info;
|
||||
struct trusty_startup_param startup_param;
|
||||
};
|
||||
uint8_t page[CPU_PAGE_SIZE];
|
||||
} first_page;
|
||||
|
||||
/* The left memory is for trusty's code/data/heap/stack
|
||||
*/
|
||||
uint8_t left_mem[0];
|
||||
};
|
||||
|
||||
_Static_assert(sizeof(struct trusty_startup_param)
|
||||
+ sizeof(struct key_info) < 0x1000,
|
||||
"trusty_startup_param + key_info > 1Page size(4KB)!");
|
||||
|
||||
#define save_segment(seg, SEG_NAME) \
|
||||
{ \
|
||||
seg.selector = exec_vmread(VMX_GUEST_##SEG_NAME##_SEL); \
|
||||
@ -239,3 +271,104 @@ void switch_world(struct vcpu *vcpu, int next_world)
|
||||
/* Update world index */
|
||||
arch_vcpu->cur_context = next_world;
|
||||
}
|
||||
|
||||
/* Put key_info and trusty_startup_param in the first Page of Trusty
|
||||
* runtime memory
|
||||
*/
|
||||
static void setup_trusty_info(struct vcpu *vcpu,
|
||||
uint32_t mem_size, uint64_t mem_base_hpa)
|
||||
{
|
||||
struct trusty_mem *mem;
|
||||
|
||||
mem = (struct trusty_mem *)(HPA2HVA(mem_base_hpa));
|
||||
|
||||
/* TODO: prepare vkey_info */
|
||||
|
||||
/* Prepare trusty startup info */
|
||||
mem->first_page.startup_param.size_of_this_struct =
|
||||
sizeof(struct trusty_startup_param);
|
||||
mem->first_page.startup_param.mem_size = mem_size;
|
||||
mem->first_page.startup_param.tsc_per_ms = TIME_MS_DELTA;
|
||||
mem->first_page.startup_param.trusty_mem_base = TRUSTY_EPT_REBASE_GPA;
|
||||
|
||||
/* According to trusty boot protocol, it will use RDI as the
|
||||
* address(GPA) of startup_param on boot. Currently, the startup_param
|
||||
* is put in the first page of trusty memory just followed by key_info.
|
||||
*/
|
||||
vcpu->arch_vcpu.contexts[SECURE_WORLD].guest_cpu_regs.regs.rdi
|
||||
= (uint64_t)TRUSTY_EPT_REBASE_GPA + sizeof(struct key_info);
|
||||
}
|
||||
|
||||
/* Secure World will reuse environment of UOS_Loder since they are
|
||||
* both booting from and running in 64bit mode, except GP registers.
|
||||
* RIP, RSP and RDI are specified below, other GP registers are leaved
|
||||
* as 0.
|
||||
*/
|
||||
static void init_secure_world_env(struct vcpu *vcpu,
|
||||
uint64_t entry_gpa,
|
||||
uint64_t base_hpa,
|
||||
uint32_t size)
|
||||
{
|
||||
vcpu->arch_vcpu.inst_len = 0;
|
||||
vcpu->arch_vcpu.contexts[SECURE_WORLD].rip = entry_gpa;
|
||||
vcpu->arch_vcpu.contexts[SECURE_WORLD].rsp =
|
||||
TRUSTY_EPT_REBASE_GPA + size;
|
||||
exec_vmwrite(VMX_GUEST_RSP,
|
||||
TRUSTY_EPT_REBASE_GPA + size);
|
||||
|
||||
setup_trusty_info(vcpu, size, base_hpa);
|
||||
}
|
||||
|
||||
bool initialize_trusty(struct vcpu *vcpu, uint64_t param)
|
||||
{
|
||||
uint64_t trusty_entry_gpa, trusty_base_gpa, trusty_base_hpa;
|
||||
struct vm *vm = vcpu->vm;
|
||||
struct trusty_boot_param *boot_param =
|
||||
(struct trusty_boot_param *)(gpa2hpa(vm, param));
|
||||
|
||||
if (sizeof(struct trusty_boot_param) !=
|
||||
boot_param->size_of_this_struct) {
|
||||
pr_err("%s: sizeof(struct trusty_boot_param) mismatch!\n",
|
||||
__func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (boot_param->version != TRUSTY_VERSION) {
|
||||
pr_err("%s: version of(trusty_boot_param) mismatch!\n",
|
||||
__func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!boot_param->entry_point) {
|
||||
pr_err("%s: Invalid entry point\n", __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!boot_param->base_addr) {
|
||||
pr_err("%s: Invalid memory base address\n", __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
trusty_entry_gpa = (uint64_t)boot_param->entry_point;
|
||||
trusty_base_gpa = (uint64_t)boot_param->base_addr;
|
||||
|
||||
create_secure_world_ept(vm, trusty_base_gpa, boot_param->mem_size,
|
||||
TRUSTY_EPT_REBASE_GPA);
|
||||
trusty_base_hpa = vm->sworld_control.sworld_memory.base_hpa;
|
||||
|
||||
exec_vmwrite64(VMX_EPT_POINTER_FULL,
|
||||
((uint64_t)vm->arch_vm.sworld_eptp) | (3<<3) | 6);
|
||||
|
||||
/* save Normal World context */
|
||||
save_world_ctx(&vcpu->arch_vcpu.contexts[NORMAL_WORLD]);
|
||||
|
||||
/* init secure world environment */
|
||||
init_secure_world_env(vcpu,
|
||||
trusty_entry_gpa - trusty_base_gpa + TRUSTY_EPT_REBASE_GPA,
|
||||
trusty_base_hpa, boot_param->mem_size);
|
||||
|
||||
/* switch to Secure World */
|
||||
vcpu->arch_vcpu.cur_context = SECURE_WORLD;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ int64_t hcall_world_switch(struct vcpu *vcpu)
|
||||
}
|
||||
|
||||
if (!vcpu->vm->arch_vm.sworld_eptp) {
|
||||
pr_err("Trusty is not launched!\n");
|
||||
pr_err("Trusty is not initialized!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -61,3 +61,31 @@ int64_t hcall_world_switch(struct vcpu *vcpu)
|
||||
switch_world(vcpu, next_world_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t hcall_initialize_trusty(struct vcpu *vcpu, uint64_t param)
|
||||
{
|
||||
if (!is_hypercall_from_ring0()) {
|
||||
pr_err("%s() is only allowed from RING-0!\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!vcpu->vm->sworld_control.sworld_enabled) {
|
||||
pr_err("Secure World is not enabled!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (vcpu->vm->arch_vm.sworld_eptp) {
|
||||
pr_err("Trusty already initialized!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ASSERT(vcpu->arch_vcpu.cur_context == NORMAL_WORLD,
|
||||
"The Trusty Initialize hypercall must be from Normal World");
|
||||
|
||||
if (!initialize_trusty(vcpu, param)) {
|
||||
pr_err("Failed to initialize trusty!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -129,6 +129,7 @@ struct secure_world_control {
|
||||
};
|
||||
|
||||
void switch_world(struct vcpu *vcpu, int next_world);
|
||||
bool initialize_trusty(struct vcpu *vcpu, uint64_t param);
|
||||
|
||||
#endif /* TRUSTY_H_ */
|
||||
|
||||
|
@ -335,6 +335,17 @@ int64_t hcall_setup_sbuf(struct vm *vm, uint64_t param);
|
||||
*/
|
||||
int64_t hcall_world_switch(struct vcpu *vcpu);
|
||||
|
||||
/**
|
||||
* @brief Initialize environment for Trusty-OS on a VCPU.
|
||||
*
|
||||
* @param VCPU Pointer to VCPU data structure
|
||||
* @param param's guest physical address. This gpa points to
|
||||
* struct trusty_boot_param
|
||||
*
|
||||
* @return 0 on success, non-zero on error.
|
||||
*/
|
||||
int64_t hcall_initialize_trusty(struct vcpu *vcpu, uint64_t param);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
@ -95,7 +95,7 @@
|
||||
|
||||
/* Trusty */
|
||||
#define HC_ID_TRUSTY_BASE 0x70UL
|
||||
#define HC_LAUNCH_TRUSTY _HC_ID(HC_ID, HC_ID_TRUSTY_BASE + 0x00)
|
||||
#define HC_INITIALIZE_TRUSTY _HC_ID(HC_ID, HC_ID_TRUSTY_BASE + 0x00)
|
||||
#define HC_WORLD_SWITCH _HC_ID(HC_ID, HC_ID_TRUSTY_BASE + 0x01)
|
||||
#define HC_GET_SEC_INFO _HC_ID(HC_ID, HC_ID_TRUSTY_BASE + 0x02)
|
||||
|
||||
@ -226,6 +226,26 @@ struct hc_api_version {
|
||||
uint32_t minor_version;
|
||||
} __aligned(8);
|
||||
|
||||
/**
|
||||
* Trusty boot params, used for HC_INITIALIZE_TRUSTY
|
||||
*/
|
||||
struct trusty_boot_param {
|
||||
/** sizeof this structure */
|
||||
uint32_t size_of_this_struct;
|
||||
|
||||
/** version of this structure */
|
||||
uint32_t version;
|
||||
|
||||
/** trusty runtime memory base address */
|
||||
uint32_t base_addr;
|
||||
|
||||
/** trusty entry point */
|
||||
uint32_t entry_point;
|
||||
|
||||
/** trusty runtime memory size */
|
||||
uint32_t mem_size;
|
||||
} __aligned(8);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user