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
|
Trusty specific Hypercalls
|
||||||
**************************
|
**************************
|
||||||
1. HC_LAUNCH_TRUSTY
|
1. HC_INITIALIZE_TRUSTY
|
||||||
->This Hypercall is used by UOSloader (User OS Bootloader) to request ACRN to launch Trusty.
|
->This Hypercall is used by UOS_Loader to request ACRN to initialize Trusty.
|
||||||
->The Trusty memory region range, entry point must be specified.
|
->The Trusty memory region range, entry point must be specified.
|
||||||
->Hypervisor needs to save current vCPU contexts (Normal World).
|
->Hypervisor needs to save current vCPU contexts (Normal World).
|
||||||
2. HC_WORLD_SWITCH
|
2. HC_WORLD_SWITCH
|
||||||
@ -60,7 +60,7 @@ Trusty specific Hypercalls
|
|||||||
|
|
||||||
API
|
API
|
||||||
---
|
---
|
||||||
1. hcall_launch_trusty(vm_t *vm);
|
1. hcall_initialize_trusty(vm_t *vm);
|
||||||
2. hcall_world_switch(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
|
UOSloader --> ACRN --> Trusty --> ACRN --> UOSloader
|
||||||
|
|
||||||
Detail:
|
Detail:
|
||||||
1. UOSloader
|
1. UOS_Loader
|
||||||
1.1 load and verify trusty image from virtual disk.
|
1.1 load and verify trusty image from virtual disk.
|
||||||
1.2 allocate runtime memory for trusty.
|
1.2 allocate runtime memory for trusty.
|
||||||
1.3 do ELF relocation of trusty image and get entry address.
|
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.
|
1.4 call HC_INITIALIZE_TRUSTY with trusty memory base and entry address.
|
||||||
2. ACRN(HC_LAUNCH_TRUSTY)
|
2. ACRN(HC_INITIALIZE_TRUSTY)
|
||||||
2.1 save World context for Normal World.
|
2.1 save World context for Normal World.
|
||||||
2.2 init World context for Secure World(RIP, RSP, EPT, etc.).
|
2.2 init World context for Secure World(RIP, RSP, EPT, etc.).
|
||||||
2.3 resume to Secure World.
|
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.
|
3.2 call HC_WORLD_SWITCH to switch back to Normal World if boot completed.
|
||||||
4. ACRN(HC_WORLD_SWITCH)
|
4. ACRN(HC_WORLD_SWITCH)
|
||||||
4.1 save World context for the World which caused this vmexit(Secure World)
|
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.2 restore World context for next World(Normal World(UOS_Loader))
|
||||||
4.3 resume to next World(UOSloader)
|
4.3 resume to next World(UOS_Loader)
|
||||||
5. UOSloader
|
5. UOS_Loader
|
||||||
5.1 continue to boot.
|
5.1 continue to boot.
|
||||||
|
|
||||||
|
|
||||||
|
@ -138,6 +138,10 @@ int vmcall_handler(struct vcpu *vcpu)
|
|||||||
ret = hcall_world_switch(vcpu);
|
ret = hcall_world_switch(vcpu);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case HC_INITIALIZE_TRUSTY:
|
||||||
|
ret = hcall_initialize_trusty(vcpu, param1);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
pr_err("op %d: Invalid hypercall\n", hypcall_id);
|
pr_err("op %d: Invalid hypercall\n", hypcall_id);
|
||||||
ret = -1;
|
ret = -1;
|
||||||
|
@ -39,6 +39,38 @@ _Static_assert(NR_WORLD == 2, "Only 2 Worlds supported!");
|
|||||||
/* Trusty EPT rebase gpa: 511G */
|
/* Trusty EPT rebase gpa: 511G */
|
||||||
#define TRUSTY_EPT_REBASE_GPA (511ULL*1024ULL*1024ULL*1024ULL)
|
#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) \
|
#define save_segment(seg, SEG_NAME) \
|
||||||
{ \
|
{ \
|
||||||
seg.selector = exec_vmread(VMX_GUEST_##SEG_NAME##_SEL); \
|
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 */
|
/* Update world index */
|
||||||
arch_vcpu->cur_context = next_world;
|
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) {
|
if (!vcpu->vm->arch_vm.sworld_eptp) {
|
||||||
pr_err("Trusty is not launched!\n");
|
pr_err("Trusty is not initialized!\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,3 +61,31 @@ int64_t hcall_world_switch(struct vcpu *vcpu)
|
|||||||
switch_world(vcpu, next_world_id);
|
switch_world(vcpu, next_world_id);
|
||||||
return 0;
|
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);
|
void switch_world(struct vcpu *vcpu, int next_world);
|
||||||
|
bool initialize_trusty(struct vcpu *vcpu, uint64_t param);
|
||||||
|
|
||||||
#endif /* TRUSTY_H_ */
|
#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);
|
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 */
|
/* Trusty */
|
||||||
#define HC_ID_TRUSTY_BASE 0x70UL
|
#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_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)
|
#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;
|
uint32_t minor_version;
|
||||||
} __aligned(8);
|
} __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