Add IgvmNativeVpContextX64 struct holding the register state (see igvm spec), and the qigvm_x86_load_context() function to load the register state.
Wire up using two new functions: qigvm_x86_set_vp_context() is called from igvm file handling code and stores the boot processor context. qigvm_x86_bsp_reset() is called from i386 target cpu reset code and loads the context into the cpu registers. Reviewed-by: Stefano Garzarella <[email protected]> Reviewed-by: Luigi Leonardi <[email protected]> Signed-off-by: Gerd Hoffmann <[email protected]> Message-ID: <[email protected]> --- include/system/igvm.h | 2 + target/i386/cpu.h | 3 + backends/igvm.c | 30 +++++----- stubs/igvm.c | 5 ++ target/i386/cpu.c | 6 ++ target/i386/igvm.c | 134 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 165 insertions(+), 15 deletions(-) diff --git a/include/system/igvm.h b/include/system/igvm.h index 3f72a40b8897..48ce20604259 100644 --- a/include/system/igvm.h +++ b/include/system/igvm.h @@ -23,5 +23,7 @@ int qigvm_process_file(IgvmCfg *igvm, ConfidentialGuestSupport *cgs, int qigvm_x86_get_mem_map_entry(int index, ConfidentialGuestMemoryMapEntry *entry, Error **errp); +int qigvm_x86_set_vp_context(void *data, int index, + Error **errp); #endif diff --git a/target/i386/cpu.h b/target/i386/cpu.h index d0da9bfe58ce..cee1f692a1c3 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -2868,6 +2868,9 @@ void x86_cpu_dump_local_apic_state(CPUState *cs, int flags); #endif +/* igvm.c */ +void qigvm_x86_bsp_reset(CPUX86State *env); + /* cpu.c */ bool cpu_is_bsp(X86CPU *cpu); diff --git a/backends/igvm.c b/backends/igvm.c index 2ab7a9d96565..905bd8d98994 100644 --- a/backends/igvm.c +++ b/backends/igvm.c @@ -432,18 +432,6 @@ static int qigvm_directive_vp_context(QIgvm *ctx, const uint8_t *header_data, return 0; } - /* - * A confidential guest support object must be provided for setting - * a VP context. - */ - if (!ctx->cgs) { - error_setg( - errp, - "A VP context is present in the IGVM file but is not supported " - "by the current system."); - return -1; - } - data_handle = igvm_get_header_data(ctx->file, IGVM_HEADER_SECTION_DIRECTIVE, ctx->current_header_index); if (data_handle < 0) { @@ -453,9 +441,21 @@ static int qigvm_directive_vp_context(QIgvm *ctx, const uint8_t *header_data, } data = (uint8_t *)igvm_get_buffer(ctx->file, data_handle); - result = ctx->cgsc->set_guest_state( - vp_context->gpa, data, igvm_get_buffer_size(ctx->file, data_handle), - CGS_PAGE_TYPE_VMSA, vp_context->vp_index, errp); + + if (ctx->cgs) { + result = ctx->cgsc->set_guest_state( + vp_context->gpa, data, igvm_get_buffer_size(ctx->file, data_handle), + CGS_PAGE_TYPE_VMSA, vp_context->vp_index, errp); + } else if (target_arch() == SYS_EMU_TARGET_X86_64) { + result = qigvm_x86_set_vp_context(data, vp_context->vp_index, errp); + } else { + error_setg( + errp, + "A VP context is present in the IGVM file but is not supported " + "by the current system."); + result = -1; + } + igvm_free_buffer(ctx->file, data_handle); if (result < 0) { return result; diff --git a/stubs/igvm.c b/stubs/igvm.c index c32058eb2a6e..17cd1e903e35 100644 --- a/stubs/igvm.c +++ b/stubs/igvm.c @@ -19,3 +19,8 @@ int qigvm_x86_get_mem_map_entry(int index, { return -1; } + +int qigvm_x86_set_vp_context(void *data, int index, Error **errp) +{ + return -1; +} diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 0a66e1fec939..641777578637 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -8770,6 +8770,12 @@ static void x86_cpu_reset_hold(Object *obj, ResetType type) cs->halted = !cpu_is_bsp(cpu); +#if defined(CONFIG_IGVM) + if (cpu_is_bsp(cpu)) { + qigvm_x86_bsp_reset(env); + } +#endif + if (kvm_enabled()) { kvm_arch_reset_vcpu(cpu); } diff --git a/target/i386/igvm.c b/target/i386/igvm.c index 2ed6cd052c79..457c253b030c 100644 --- a/target/i386/igvm.c +++ b/target/i386/igvm.c @@ -11,9 +11,115 @@ #include "qemu/osdep.h" +#include "cpu.h" #include "hw/i386/e820_memory_layout.h" #include "system/igvm.h" +struct IgvmNativeVpContextX64 { + uint64_t rax; + uint64_t rcx; + uint64_t rdx; + uint64_t rbx; + uint64_t rsp; + uint64_t rbp; + uint64_t rsi; + uint64_t rdi; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + uint64_t rip; + uint64_t rflags; + uint64_t idtr_base; + uint16_t idtr_limit; + uint16_t reserved[2]; + uint16_t gdtr_limit; + uint64_t gdtr_base; + + uint16_t code_selector; + uint16_t code_attributes; + uint32_t code_base; + uint32_t code_limit; + + uint16_t data_selector; + uint16_t data_attributes; + uint32_t data_base; + uint32_t data_limit; + + uint64_t gs_base; + uint64_t cr0; + uint64_t cr3; + uint64_t cr4; + uint64_t efer; +}; + +#define FLAGS_TO_SEGCACHE(flags) \ + (((unsigned int)flags) << 8) + +static void qigvm_x86_load_context(struct IgvmNativeVpContextX64 *context, + CPUX86State *env) +{ + cpu_load_efer(env, context->efer); + cpu_x86_update_cr4(env, context->cr4); + cpu_x86_update_cr0(env, context->cr0); + cpu_x86_update_cr3(env, context->cr3); + + cpu_x86_load_seg_cache( + env, R_CS, context->code_selector, + context->code_base, context->code_limit, + FLAGS_TO_SEGCACHE(context->code_attributes)); + cpu_x86_load_seg_cache( + env, R_DS, context->data_selector, + context->data_base, context->data_limit, + FLAGS_TO_SEGCACHE(context->data_attributes)); + cpu_x86_load_seg_cache( + env, R_ES, context->data_selector, + context->data_base, context->data_limit, + FLAGS_TO_SEGCACHE(context->data_attributes)); + cpu_x86_load_seg_cache( + env, R_FS, context->data_selector, + context->data_base, context->data_limit, + FLAGS_TO_SEGCACHE(context->data_attributes)); + cpu_x86_load_seg_cache( + env, R_GS, context->data_selector, + context->data_base, context->data_limit, + FLAGS_TO_SEGCACHE(context->data_attributes)); + cpu_x86_load_seg_cache( + env, R_SS, context->data_selector, + context->data_base, context->data_limit, + FLAGS_TO_SEGCACHE(context->data_attributes)); + + env->gdt.base = context->gdtr_base; + env->gdt.limit = context->gdtr_limit; + env->idt.base = context->idtr_base; + env->idt.limit = context->idtr_limit; + + env->regs[R_EAX] = context->rax; + env->regs[R_ECX] = context->rcx; + env->regs[R_EDX] = context->rdx; + env->regs[R_EBX] = context->rbx; + env->regs[R_ESP] = context->rsp; + env->regs[R_EBP] = context->rbp; + env->regs[R_ESI] = context->rsi; + env->regs[R_EDI] = context->rdi; +#ifdef TARGET_X86_64 + env->regs[R_R8] = context->r8; + env->regs[R_R9] = context->r9; + env->regs[R_R10] = context->r10; + env->regs[R_R11] = context->r11; + env->regs[R_R12] = context->r12; + env->regs[R_R13] = context->r13; + env->regs[R_R14] = context->r14; + env->regs[R_R15] = context->r15; +#endif + env->eip = context->rip; + env->eflags = context->rflags; +} + /* * convert e820 table into igvm memory map */ @@ -44,3 +150,31 @@ int qigvm_x86_get_mem_map_entry(int index, } return 0; } + +/* + * set initial cpu context + */ +static struct IgvmNativeVpContextX64 *bsp_context; + +int qigvm_x86_set_vp_context(void *data, int index, Error **errp) +{ + if (index != 0) { + error_setg(errp, "context can be set for BSP only"); + return -1; + } + + if (bsp_context == NULL) { + bsp_context = g_new0(struct IgvmNativeVpContextX64, 1); + } + memcpy(bsp_context, data, sizeof(struct IgvmNativeVpContextX64)); + return 0; +} + +void qigvm_x86_bsp_reset(CPUX86State *env) +{ + if (bsp_context == NULL) { + return; + } + + qigvm_x86_load_context(bsp_context, env); +} -- 2.51.1
