diff options
| author | Alexander Potapenko <glider@google.com> | 2026-01-20 11:24:50 +0100 |
|---|---|---|
| committer | Alexander Potapenko <glider@google.com> | 2026-01-20 11:17:07 +0000 |
| commit | 88c380012ee818101167d1400550823398a15845 (patch) | |
| tree | f4888efd28872940c3454db27fa43163449689bb /executor | |
| parent | 06648d9ccf5ec6f9453ef09b0fdbdebf020ee0f8 (diff) | |
executor: sys/linux: SYZOS: add AMD VMLOAD and VMSAVE primitives
This patch introduces SYZOS_API_NESTED_AMD_VMLOAD and
SYZOS_API_NESTED_AMD_VMSAVE.
These primitives allow the L1 guest to execute the VMLOAD and VMSAVE
instructions, which load/store additional guest state (FS, GS, TR, LDTR,
etc.) to/from the VMCB specified by the 'vm_id' argument.
This stresses the KVM L0 instruction emulator, which must validate the
L1-provided physical address in RAX and perform the state transfer.
Diffstat (limited to 'executor')
| -rw-r--r-- | executor/common_kvm_amd64_syzos.h | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/executor/common_kvm_amd64_syzos.h b/executor/common_kvm_amd64_syzos.h index 31f62a79c..5584a62b9 100644 --- a/executor/common_kvm_amd64_syzos.h +++ b/executor/common_kvm_amd64_syzos.h @@ -38,6 +38,8 @@ typedef enum { SYZOS_API_NESTED_AMD_CLGI = 383, SYZOS_API_NESTED_AMD_INJECT_EVENT = 384, SYZOS_API_NESTED_AMD_SET_INTERCEPT = 385, + SYZOS_API_NESTED_AMD_VMLOAD = 386, + SYZOS_API_NESTED_AMD_VMSAVE = 387, SYZOS_API_STOP, // Must be the last one } syzos_api_id; @@ -123,6 +125,8 @@ GUEST_CODE static void guest_handle_nested_amd_stgi(); GUEST_CODE static void guest_handle_nested_amd_clgi(); GUEST_CODE static void guest_handle_nested_amd_inject_event(struct api_call_5* cmd, uint64 cpu_id); GUEST_CODE static void guest_handle_nested_amd_set_intercept(struct api_call_5* cmd, uint64 cpu_id); +GUEST_CODE static void guest_handle_nested_amd_vmload(struct api_call_1* cmd, uint64 cpu_id); +GUEST_CODE static void guest_handle_nested_amd_vmsave(struct api_call_1* cmd, uint64 cpu_id); typedef enum { UEXIT_END = (uint64)-1, @@ -253,6 +257,12 @@ guest_main(uint64 size, uint64 cpu) } else if (call == SYZOS_API_NESTED_AMD_SET_INTERCEPT) { // Set/Clear specific intercept bits in the VMCB. guest_handle_nested_amd_set_intercept((struct api_call_5*)cmd, cpu); + } else if (call == SYZOS_API_NESTED_AMD_VMLOAD) { + // Execute VMLOAD to load state from VMCB. + guest_handle_nested_amd_vmload((struct api_call_1*)cmd, cpu); + } else if (call == SYZOS_API_NESTED_AMD_VMSAVE) { + // Execute VMSAVE to save state to VMCB. + guest_handle_nested_amd_vmsave((struct api_call_1*)cmd, cpu); } addr += cmd->size; size -= cmd->size; @@ -1392,4 +1402,26 @@ guest_handle_nested_amd_set_intercept(struct api_call_5* cmd, uint64 cpu_id) vmcb_write32(vmcb_addr, (uint16)offset, current); } +GUEST_CODE static noinline void +guest_handle_nested_amd_vmload(struct api_call_1* cmd, uint64 cpu_id) +{ + if (get_cpu_vendor() != CPU_VENDOR_AMD) + return; + uint64 vm_id = cmd->arg; + uint64 vmcb_pa = X86_SYZOS_ADDR_VMCS_VMCB(cpu_id, vm_id); + + asm volatile("vmload %%rax" ::"a"(vmcb_pa) : "memory"); +} + +GUEST_CODE static noinline void +guest_handle_nested_amd_vmsave(struct api_call_1* cmd, uint64 cpu_id) +{ + if (get_cpu_vendor() != CPU_VENDOR_AMD) + return; + uint64 vm_id = cmd->arg; + uint64 vmcb_pa = X86_SYZOS_ADDR_VMCS_VMCB(cpu_id, vm_id); + + asm volatile("vmsave %%rax" ::"a"(vmcb_pa) : "memory"); +} + #endif // EXECUTOR_COMMON_KVM_AMD64_SYZOS_H |
