From 95490bcce0b997a352b8a7de532abb750d9c63e2 Mon Sep 17 00:00:00 2001 From: hanbings Date: Thu, 12 Dec 2024 01:05:49 +0800 Subject: [PATCH 1/4] Upgrade dependencies and fix build. --- Cargo.toml | 4 ++-- src/lib.rs | 7 ++++++- src/svm/mod.rs | 21 +++++++++++++++++++++ src/vmx/vcpu.rs | 10 +++++----- 4 files changed, 34 insertions(+), 8 deletions(-) create mode 100644 src/svm/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 14beca6..9c34a26 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,6 @@ axaddrspace = { git = "https://github.com/arceos-hypervisor/axaddrspace.git" } axvcpu = { git = "https://github.com/arceos-hypervisor/axvcpu.git" } [features] -default = ["vmx"] +default = ["vmx", "svm"] vmx = [] -amd = [] +svm = [] diff --git a/src/lib.rs b/src/lib.rs index d92d0b1..b2d11e9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,6 @@ #![no_std] #![feature(doc_cfg)] #![feature(concat_idents)] -#![feature(asm_const)] #![feature(naked_functions)] #![doc = include_str!("../README.md")] @@ -27,6 +26,12 @@ cfg_if::cfg_if! { } } +cfg_if::cfg_if! { + if #[cfg(feature = "svm")] { + mod svm; + } +} + pub use ept::GuestPageWalkInfo; pub use regs::GeneralRegisters; pub use vender::has_hardware_support; diff --git a/src/svm/mod.rs b/src/svm/mod.rs new file mode 100644 index 0000000..ffe898b --- /dev/null +++ b/src/svm/mod.rs @@ -0,0 +1,21 @@ +use axerrno::ax_err_type; + +pub fn has_hardware_support() -> bool { + if let Some(feature) = raw_cpuid::CpuId::new().get_feature_info() { + feature.has_vmx() + } else { + false + } +} + +pub fn read_vmcs_revision_id() -> u32 { + 0 +} + +fn as_axerr(err: x86::vmx::VmFail) -> axerrno::AxError { + use x86::vmx::VmFail; + match err { + VmFail::VmFailValid => ax_err_type!(BadState, "Unsupported instruction"), + VmFail::VmFailInvalid => ax_err_type!(BadState, "Unsupported instruction"), + } +} diff --git a/src/vmx/vcpu.rs b/src/vmx/vcpu.rs index e772cbf..04c7117 100644 --- a/src/vmx/vcpu.rs +++ b/src/vmx/vcpu.rs @@ -1,7 +1,7 @@ use alloc::collections::VecDeque; use bit_field::BitField; use core::fmt::{Debug, Formatter, Result}; -use core::{arch::asm, mem::size_of}; +use core::{arch::naked_asm, mem::size_of}; use raw_cpuid::CpuId; use x86::bits64::vmx; use x86::controlregs::{xcr0 as xcr0_read, xcr0_write, Xcr0}; @@ -717,7 +717,7 @@ impl VmxVcpu { /// Get ready then vmlaunch or vmresume. macro_rules! vmx_entry_with { ($instr:literal) => { - asm!( + naked_asm!( save_regs_to_stack!(), // save host status "mov [rdi + {host_stack_size}], rsp", // save current RSP to Vcpu::host_stack_top "mov rsp, rdi", // set RSP to guest regs area @@ -726,7 +726,7 @@ macro_rules! vmx_entry_with { "jmp {failed}", host_stack_size = const size_of::(), failed = sym Self::vmx_entry_failed, - options(noreturn), + options(), ) } } @@ -757,13 +757,13 @@ impl VmxVcpu { /// /// The return value is a dummy value. unsafe extern "C" fn vmx_exit(&mut self) -> usize { - asm!( + naked_asm!( save_regs_to_stack!(), // save guest status "mov rsp, [rsp + {host_stack_top}]", // set RSP to Vcpu::host_stack_top restore_regs_from_stack!(), // restore host status "ret", host_stack_top = const size_of::(), - options(noreturn), + options(), ); } From 32aff3ddccb320f73c1d78667010606236102661 Mon Sep 17 00:00:00 2001 From: hanbings Date: Thu, 12 Dec 2024 01:20:55 +0800 Subject: [PATCH 2/4] Upgrade the rust toolchain version. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2074db9..0b48084 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,7 @@ jobs: strategy: fail-fast: false matrix: - rust-toolchain: [nightly-2024-05-02, nightly-2024-08-24] + rust-toolchain: [nightly-2024-11-28] targets: [x86_64-unknown-none] steps: - uses: actions/checkout@v4 From 67badfb515b3b76ff0dfad65c74ba7079d2189ed Mon Sep 17 00:00:00 2001 From: hanbings Date: Wed, 18 Dec 2024 03:43:37 +0800 Subject: [PATCH 3/4] Add vmcb data structure for svm. --- Cargo.toml | 1 + README.md | 3 +- src/lib.rs | 4 +- src/svm/definitions.rs | 1 + src/svm/instructions.rs | 1 + src/svm/mod.rs | 24 +- src/svm/percpu.rs | 1 + src/svm/vcpu.rs | 1 + src/svm/vmcb.rs | 612 ++++++++++++++++++++++++++++++++++++++++ 9 files changed, 626 insertions(+), 22 deletions(-) create mode 100644 src/svm/definitions.rs create mode 100644 src/svm/instructions.rs create mode 100644 src/svm/percpu.rs create mode 100644 src/svm/vcpu.rs create mode 100644 src/svm/vmcb.rs diff --git a/Cargo.toml b/Cargo.toml index 9c34a26..daefa5c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] log = "0.4.19" cfg-if = "1.0" +bilge = "0.2.0" bitflags = "2.2" bit_field = "0.10" x86 = "0.52" diff --git a/README.md b/README.md index 66e4e58..3fe78d1 100644 --- a/README.md +++ b/README.md @@ -26,5 +26,4 @@ impl axvm::PhysFrameIf for PhysFrameIfImpl { fn phys_to_virt(paddr: PhysAddr) -> VirtAddr { // Your implementation here } -} -``` \ No newline at end of file +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index b2d11e9..0965df5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,8 +27,8 @@ cfg_if::cfg_if! { } cfg_if::cfg_if! { - if #[cfg(feature = "svm")] { - mod svm; + if #[cfg(feature = "svm")]{ + pub mod svm; } } diff --git a/src/svm/definitions.rs b/src/svm/definitions.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/svm/definitions.rs @@ -0,0 +1 @@ + diff --git a/src/svm/instructions.rs b/src/svm/instructions.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/svm/instructions.rs @@ -0,0 +1 @@ + diff --git a/src/svm/mod.rs b/src/svm/mod.rs index ffe898b..e111dba 100644 --- a/src/svm/mod.rs +++ b/src/svm/mod.rs @@ -1,21 +1,9 @@ -use axerrno::ax_err_type; +mod definitions; +mod instructions; +mod percpu; +mod vcpu; +mod vmcb; pub fn has_hardware_support() -> bool { - if let Some(feature) = raw_cpuid::CpuId::new().get_feature_info() { - feature.has_vmx() - } else { - false - } -} - -pub fn read_vmcs_revision_id() -> u32 { - 0 -} - -fn as_axerr(err: x86::vmx::VmFail) -> axerrno::AxError { - use x86::vmx::VmFail; - match err { - VmFail::VmFailValid => ax_err_type!(BadState, "Unsupported instruction"), - VmFail::VmFailInvalid => ax_err_type!(BadState, "Unsupported instruction"), - } + raw_cpuid::CpuId::new().get_svm_info().is_some() } diff --git a/src/svm/percpu.rs b/src/svm/percpu.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/svm/percpu.rs @@ -0,0 +1 @@ + diff --git a/src/svm/vcpu.rs b/src/svm/vcpu.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/svm/vcpu.rs @@ -0,0 +1 @@ + diff --git a/src/svm/vmcb.rs b/src/svm/vmcb.rs new file mode 100644 index 0000000..b3e903e --- /dev/null +++ b/src/svm/vmcb.rs @@ -0,0 +1,612 @@ +use bilge::prelude::*; + +#[repr(C)] +#[derive(Clone, Copy, PartialEq)] +pub struct Vmcb { + control_area: VmcbControlArea, + state_save_area: VmcbStateSaveArea, +} + +#[repr(C)] +#[derive(Clone, Copy, PartialEq)] +pub struct VmcbControlArea { + // intercept vector 0 + intercept_cr_read: u16, + intercept_cr_write: u16, + // intercept vector 1 + intercept_dr_read: u16, + intercept_dr_write: u16, + // intercept vector 2 + intercept_exception: u32, + // intercept vector 3 + intercept_vector3: VmcbInterceptVector3, + // intercept vector 4 + intercept_vector4: VmcbInterceptVector4, + // intercept vector 5 + intercept_vector5: VmcbInterceptVector5, + + // reserved 0x18 - 0x3b + reserved_0x18_0x3b: [u8; 0x3b - 0x18], + + // PAUSE Filter Threshold + pause_filter_threshold: u16, + // PAUSE Filter Count + pause_filter_count: u16, + + // Physical base address, bits 11:0 are ignored + // Physical base address of IOPM + iopm_base_pa: u64, + msrpm_base_pa: u64, + tsc_offset: u64, + + // Guest state + guest: VmcbGuest, + vm_interrupt_control_flags: VmInterruptControlFlags, + vm_shadow_interrupt: VmShadowInterrupt, + exit_code: u64, + exit_info_1: u64, + exit_info_2: u64, + exit_init_info: u64, + nested_paging_flags: NestedPagingFlags, + avic_control_flags: AvicControlFlags, + + // Guest Physical Address of GHCB + ghcb_pa: u64, + // EVENTINJ—Event injection + event_injection: u64, + // nested paging + n_cr3: u64, + + // LBR Virtualization Flags + lbr_virtualization_flags: LbrVirtualizationFlags, + + // Clean Bits + clean_bits: VmcbCleanBits, + + // Next sequential instruction pointer + n_rip: u64, + + // Instruction Fetch Count + instruction_fetch_count: InstructionFetchCount, + + // AVIC APIC_BACKING_PAGE Pointer + avic_backing_page_pointer: AvicBackingPagePointer, + + // reserved 0xef - 0xe8 + reserved_0xef_0xe8: [u8; 0xef - 0xe8], + + // AVIC Logical Backing Page Pointer + avic_logical_backing_page_pointer: AvicBackingPagePointer, + // AVIC Physical Backing Page Pointer + avic_physical_backing_page_pointer: AvicBackingPagePointer, + + // reserved 0x100 - 0x107 + reserved_0x100_0x107: [u8; 0x107 - 0x100], + + // VMSA Pointer + vmsa_pointer: VmcbStateSaveAreaPointer, + + vmgexit_rax: u64, + vmgrexit_cpl: u8, + + // bus lock threshold counter + bus_lock_threshold_counter: u16, + + // reserved 0x133 - 0x128 + reserved_0x138_0x128: [u8; 0x133 - 0x128], + + // update irr ??? len = 0 + update_irr: [u8; 0x138 - 0x133], + + // SEV + sev_features_mask: SevFeaturesMask, + guest_sev_features: GuestSevFeatures, + + // reserved 0x148 - 0x150 + reserved_0x148_0x150: [u8; 0x150 - 0x148], + + // reserved 0x170 - 0x150 + requested_irr: [u8; 0x170 - 0x150], + + // reserved 0x3df - 0x170 + reserved_0x120_0x3df: [u8; 0x3df - 0x170], + + // reserved for host usage + reserved_0x3e0_0x3ff: [u8; 0x3ff - 0x3e0], +} + +impl VmcbControlArea { + #[allow(unused)] + pub fn tlb_control_description(&self) -> &'static str { + match self.guest.tlb_control() { + 0x00 => "Do nothing", + 0x01 => "Flush entire TLB (all entries, all ASIDs) on VMRUN", + 0x03 => "Flush this guest's TLB entries", + 0x07 => "Flush this guest's non-global TLB entries", + _ => "Reserved or Invalid encoding", + } + } +} + +#[repr(C)] +#[bitsize(32)] +#[derive(Clone, Copy, PartialEq, FromBits)] +pub struct VmcbInterceptVector3 { + intercept_intr: u1, + intercept_nmi: u1, + intercept_smi: u1, + intercept_init: u1, + intercept_vintr: u1, + // intercept CR0 writes that change bits other than CR0.TS or CR0.MP + intercept_cr0_writes: u1, + + // descriptor tables intercept + intercept_idtr_reads: u1, + intercept_gdtr_reads: u1, + intercept_ldtr_reads: u1, + intercept_tr_reads: u1, + intercept_idtr_writes: u1, + intercept_gdtr_writes: u1, + intercept_ldtr_writes: u1, + intercept_tr_writes: u1, + + // intercept instruction + intercept_rdtsc: u1, + intercept_rdpmc: u1, + intercept_pushf: u1, + intercept_popf: u1, + intercept_cpuid: u1, + intercept_rsm: u1, + intercept_iret: u1, + intercept_intn: u1, + intercept_invd: u1, + intercept_pause: u1, + intercept_hlt: u1, + intercept_invlpg: u1, + intercept_invlpga: u1, + intercept_ioio_prot: u1, + intercept_msr_prot: u1, + intercept_task_switch: u1, + + // intercept processor "freezing" during legacy FERR handling + intercept_ferr_freeze: u1, + intercept_shutdown_event: u1, +} + +#[repr(C)] +#[bitsize(32)] +#[derive(Clone, Copy, PartialEq, FromBits)] +pub struct VmcbInterceptVector4 { + intercept_vmrun: u1, + intercept_vmmcall: u1, + intercept_vmload: u1, + intercept_vmsave: u1, + intercept_stgi: u1, + intercept_clgi: u1, + intercept_skinit: u1, + intercept_rdtscp: u1, + intercept_icebp: u1, + // WBINVD and WBNOINVD + intercept_wbinvd_wbnoinvd: u1, + // MONITOR / MONITORX + intercept_monitor: u1, + // MWAIT / MWAITX instruction unconditional + intercept_mwait: u1, + // MWAIT / MWAITX instruction if monitor hardware is armed + intercept_mwait_hw_armed: u1, + intercept_xsetbv: u1, + intercept_rdpru: u1, + intercept_efer_writes: u1, + intercept_cr0: u1, + intercept_cr1: u1, + intercept_cr2: u1, + intercept_cr3: u1, + intercept_cr4: u1, + intercept_cr5: u1, + intercept_cr6: u1, + intercept_cr7: u1, + intercept_dr8: u1, + intercept_dr9: u1, + intercept_dr10: u1, + intercept_dr11: u1, + intercept_dr12: u1, + intercept_dr13: u1, + intercept_dr14: u1, + intercept_dr15: u1, +} + +#[repr(C)] +#[bitsize(32)] +#[derive(Clone, Copy, PartialEq, FromBits)] +pub struct VmcbInterceptVector5 { + intercept_invlpgb: u1, + intercept_illegal_invlpgb: u1, + intercept_invpcid: u1, + intercept_mcommit: u1, + // Intercept TLB invalidation. Presence of this bit + // is indicated by CPUID Fn8000_000A, EDX[24] = 1 + intercept_tlbsync: u1, + // Intercept HLT instruction if a virtual interrupt is not pending + intercept_hlt: u1, + reserve: u26, +} + +#[repr(C)] +#[bitsize(64)] +#[derive(Clone, Copy, PartialEq, FromBits)] +pub struct VmcbGuest { + // Guest Address Space Identifier (Guest ASID) + guest_asid: u32, + // TLB Control (bits 39:32) + // todo: Parse TLB Control + tlb_control: u8, + // Reserved bits (bits 63:40) + reserved: u24, +} + +#[repr(C)] +#[bitsize(64)] +#[derive(Clone, Copy, PartialEq, FromBits)] +pub struct VmInterruptControlFlags { + // Virtual TPR (bits 7:0) + // 4-bit virtual TPR value in bits 3:0 + // bits 7:4 are reserved (SBZ) + v_tpr: u4, + reserved_tpr: u4, + + // V_IRQ (bit 8) + // Nonzero if virtual INTR is pending + v_irq: u1, + + // VGIF (bit 9) + // Virtual interrupts are masked/unmasked (0: masked, 1: unmasked) + vgif: u1, + + // V_NMI (bit 11) + // Nonzero if virtual NMI is pending + v_nmi: u1, + + // V_NMI_MASK (bit 12) + // Nonzero if virtual NMI is masked + v_nmi_mask: u1, + + // Reserved bits 13:15 + // Reserved (SBZ) + reserved_nmi: u3, + + // V_INTR_PRIO (bits 19:16) + // 4-bit priority for virtual interrupt + v_intr_prio: u4, + + // V_IGN_TPR (bit 20) + // Nonzero if the current virtual interrupt ignores the (virtual) TPR + v_ign_tpr: u1, + + // Reserved bits 21:23 + // Reserved (SBZ) + reserved_intr: u3, + + // V_INTR_MASKING (bit 24) + // Virtualize masking of INTR interrupts + v_intr_masking: u1, + + // AMD Virtual GIF enabled (bit 25) + // Nonzero if AMD Virtual GIF is enabled for this guest + v_gif_enabled: u1, + + // V_NMI_ENABLE (bit 26) + // Nonzero if NMI virtualization is enabled + v_nmi_enable: u1, + + // Reserved bits 27:29 + // Reserved (SBZ) + reserved_nmi_enable: u3, + + // x2AVIC Enable (bit 30) + // Nonzero if x2AVIC is enabled + x2avic_enable: u1, + + // AVIC Enable (bit 31) + // Nonzero if AVIC is enabled + avic_enable: u1, + + // V_INTR_VECTOR (bits 39:32) + // 8-bit vector to use for this interrupt + v_intr_vector: u8, + + // Reserved bits 40:63 + // Reserved (SBZ) + reserved: u25, +} + +#[repr(C)] +#[bitsize(64)] +#[derive(Clone, Copy, PartialEq, FromBits)] +pub struct VmShadowInterrupt { + // INTERRUPT_SHADOW (bit 0) + // Guest is in an interrupt shadow (1: true, 0: false) + interrupt_shadow: u1, + + // GUEST_INTERRUPT_MASK (bit 1) + // Value of RFLAGS.IF for the guest + guest_interrupt_mask: u1, + + // Reserved bits (bits 63:2) + // 62 bits reserved (SBZ) + reserved: u62, +} + +#[repr(C)] +#[bitsize(64)] +#[derive(Clone, Copy, PartialEq, FromBits)] +pub struct NestedPagingFlags { + /// Enable nested paging + np_enable: u1, + + /// Enable Secure Encrypted Virtualization (SEV) + enable_sev: u1, + + /// Enable encrypted state for Secure Encrypted Virtualization (SEV) + enable_encrypted_state: u1, + + /// Guest Mode Execute Trap + guest_mode_execute_trap: u1, + + /// Enable supervisor shadow stack restrictions in nested page tables. + /// Support for this feature is indicated by CPUID Fn8000_000A_EDX[19] (SSSCheck). + sss_check_en: u1, + + /// Virtual Transparent Encryption + virtual_transparent_encryption: u1, + + /// Enable Read Only Guest Page Tables. + /// See "Nested Table Walk" for more information. + enable_read_only_guest_page_tables: u1, + + /// Enable INVLPGB/TLBSYNC. + /// + /// 0 - INVLPGB and TLBSYNC will result in #UD. + /// 1 - INVLPGB and TLBSYNC can be executed in guest. + /// + /// Presence of this bit is indicated by CPUID bit 8000_000A, EDX[24] = 1. + /// When in SEV-ES guest or this bit is not present, INVLPGB/TLBSYNC is always enabled in guest + enable_inv_lpgb_tlbsync: u1, + + /// Reserved (SBZ) + reserved: u56, +} + +#[repr(C)] +#[bitsize(64)] +#[derive(Clone, Copy, PartialEq, FromBits)] +pub struct AvicControlFlags { + /// Reserved (SBZ) + /// Bits 63:52 are reserved (SBZ) + reserved: u12, + + /// AVIC APIC_BAR + /// + /// Address of the APIC base for the AVIC (AMD Virtual APIC). + /// The APIC_BAR is used by AVIC to access the APIC and other + /// related functionality within the virtualized environment. + /// + /// Bits 51:0 are for AVIC APIC_BAR + apic_bar: u52, +} + +#[repr(C)] +#[bitsize(64)] +#[derive(Clone, Copy, PartialEq, FromBits)] +pub struct LbrVirtualizationFlags { + /// LBR Virtualization Enable + /// + /// 0 — Do nothing. + /// 1 — Enable LBR virtualization hardware acceleration. + lbr_virtualization_enable: u1, + + /// Virtualized VMSAVE/VMLOAD Enable + /// + /// Enables virtualized versions of VMSAVE and VMLOAD instructions. + virtualized_vmsave_vmload_enable: u1, + + /// Virtualized Instruction-Based Sampling Enable + /// + /// Enables virtualized instruction-based sampling. + /// See "Instruction-Based Sampling Virtualization" for details. + virtualized_instruction_sampling_enable: u1, + + /// Reserved (SBZ) + /// Reserved bits (63:3) + reserved: u61, +} + +#[repr(C)] +#[bitsize(64)] +#[derive(Clone, Copy, PartialEq, FromBits)] +pub struct VmcbCleanBits { + /// VMCB Clean Bits + /// + /// Represents the clean bits in the VMCB. + /// These bits are used to track the state of the VMCB, indicating which fields + /// have been modified or need to be written back to memory. + /// Bits 31:0 for VMCB Clean Bits + vmcb_clean_bits: u32, + + /// Reserved (SBZ) + /// Bits 63:32 are reserved (SBZ) + reserved: u32, +} + +#[repr(C)] +#[bitsize(128)] +#[derive(Clone, Copy, PartialEq, FromBits)] +pub struct InstructionFetchCount { + // Number of bytes fetched + number_of_bytes_fetched: u8, + // Guest instruction bytes + guest_instruction_bytes: u120, +} + +#[repr(C)] +#[bitsize(64)] +#[derive(Clone, Copy, PartialEq, FromBits)] +pub struct AvicBackingPagePointer { + /// AVIC APIC_BACKING_PAGE Pointer + /// + /// This field holds the pointer to the APIC backing page for AVIC (AMD Virtual APIC). + /// It points to the structure used by AVIC to emulate the APIC and related functionality + /// in a virtualized environment. + /// Bits 51:0 for AVIC APIC_BACKING_PAGE pointer + apic_backing_page_pointer: u52, + apic_backing_page_pointer_reserved: u12, +} + +#[repr(C)] +#[bitsize(64)] +#[derive(Clone, Copy, PartialEq, FromBits)] +pub struct AvicLogicalTablePointer { + avic_logical_table_pointer_reserved_1: u12, + avic_logical_table_pointer: u40, + avic_logical_table_pointer_reserved_2: u12, +} + +#[repr(C)] +#[bitsize(64)] +#[derive(Clone, Copy, PartialEq, FromBits)] +pub struct AvicPhysicalTablePointer { + avic_physical_table_pointer_reserved_1: u8, + avic_physical_table_pointer: u40, + avic_physical_table_pointer_reserved_2: u8, + avic_physical_max_index: u8, +} + +#[repr(C)] +#[bitsize(64)] +#[derive(Clone, Copy, PartialEq, FromBits)] +pub struct SevFeaturesMask { + allowed_sev_features_mask: u62, + reserved: u1, + allowed_sev_features_en: u1, +} + +#[repr(C)] +#[bitsize(64)] +#[derive(Clone, Copy, PartialEq, FromBits)] +pub struct GuestSevFeatures { + guest_sev_features: u62, + reserved: u2, +} + +#[repr(C)] +#[bitsize(64)] +#[derive(Clone, Copy, PartialEq, FromBits)] +pub struct VmcbStateSaveAreaPointer { + vmsa_pointer_reserved_1: u12, + vmsa_pointer: u40, + vmsa_pointer_reserved_2: u12, +} + +#[repr(C)] +#[derive(Clone, Copy, PartialEq)] +pub struct VmcbStateSaveArea { + // registers + es: VmcbRegister, + cs: VmcbRegister, + ss: VmcbRegister, + ds: VmcbRegister, + fs: VmcbRegister, + gs: VmcbRegister, + gdtr: VmcbRegister, + ldtr: VmcbRegister, + idtr: VmcbRegister, + tr: VmcbRegister, + // reserved 0xa0 - 0xca + reserved_0xa0_0xca: [u8; 0xca - 0xa0], + // If the guest is real-mode then the CPL is forced to 0; + // if the guest is virtual-mode then the CPL is forced to 3. + cpl: u8, + // reserved 0xcc + reserved_0xcc: u32, + efer: u64, + // reserved 0xd8 - 0x147 + reserved_0xd8_0xdf: [u8; 0xdf - 0xd8], + // perf control + perf_ctl0: u64, + perf_ctr0: u64, + perf_ctl1: u64, + perf_ctr1: u64, + perf_ctl2: u64, + perf_ctr2: u64, + perf_ctl3: u64, + perf_ctr3: u64, + perf_ctl4: u64, + perf_ctr4: u64, + perf_ctl5: u64, + perf_ctr5: u64, + // control registers and data registers + cr4: u64, + cr3: u64, + cr0: u64, + dr7: u64, + dr6: u64, + rfalgs: u64, + rip: u64, + // reserved 0x180 - 0x1bf + reserved_0x180_0x1bf: [u8; 0x1bf - 0x180], + instr_retired_ctr: u64, + perf_ctr_global_sts: u64, + perf_ctr_global_ctl: u64, + // reserved 0x1d4 - 1d7 + reserved_0x1d4_0x1d7: [u8; 0x1d7 - 0x1d4], + rsp: u64, + s_cet: u64, + ssp: u64, + isst_addr: u64, + rax: u64, + star: u64, + lstar: u64, + cstar: u64, + sfmask: u64, + kernel_gs_base: u64, + sysenter_cs: u64, + sysenter_esp: u64, + sysenter_eip: u64, + cr2: u64, + // reserved 248h–267h + reserved_0x248_0x267: [u8; 0x267 - 0x248], + g_pat: u64, + dbgctl: u64, + br_from: u64, + br_to: u64, + lastexcpfrom: u64, + lastexcpto: u64, + dbgextnctl: u64, + // reserved 2a0h–2dfh + reserved_0x2a0_0x2df: [u8; 0x2df - 0x2a0], + spec_ctrl: u64, + // reserved 2e8h–66fh + reserved_0x2e8_0x66f: [u8; 0x66f - 0x2e8], + // 670h - 76fh + lbr_stack: [u8; 256], + lbr_select: u64, + ibs_fetch_ctl: u64, + ibs_fetch_linaddr: u64, + ibs_op_ctl: u64, + ibs_op_rip: u64, + ibs_op_data: u64, + ibs_op_data2: u64, + ibs_op_data3: u64, + ibs_dc_linaddr: u64, + bp_ibstgt_rip: u64, + ic_ibst_extd_ctl: u64, +} + +#[repr(C)] +#[bitsize(128)] +#[derive(Clone, Copy, PartialEq, FromBits)] +pub struct VmcbRegister { + selector: u16, + attrib: u16, + limit: u32, + base: u64, +} From 83fee45b5742edb685666aebbed8939df1403e50 Mon Sep 17 00:00:00 2001 From: hanbings Date: Wed, 25 Dec 2024 02:24:37 +0800 Subject: [PATCH 4/4] Completed the AMD SVM exception types. --- src/svm/definitions.rs | 289 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 289 insertions(+) diff --git a/src/svm/definitions.rs b/src/svm/definitions.rs index 8b13789..1440d32 100644 --- a/src/svm/definitions.rs +++ b/src/svm/definitions.rs @@ -1 +1,290 @@ +use core::fmt::{Debug, Formatter, Result}; +pub struct SvmInstructionError(i32); + +impl SvmInstructionError { + pub fn as_str(&self) -> &str { + match self.0 { + 0x0 | 0x1 | 0x2 | 0x3 | 0x4 | 0x5 | 0x6 | 0x7 | 0x8 | 0x9 | 0xa | 0xb | 0xc | 0xd | 0xe | 0xf => "Cr Read", + 0x10 | 0x11 | 0x12 | 0x13 | 0x14 | 0x15 | 0x16 | 0x17 | 0x18 | 0x19 | 0x1a | 0x1b | 0x1c | 0x1d | 0x1e | 0x1f => "Cr Wirte", + 0x20 | 0x21 | 0x22 | 0x23 | 0x24 | 0x25 | 0x26 | 0x27 | 0x28 | 0x29 | 0x2a | 0x2b | 0x2c | 0x2d | 0x2e | 0x2f => "Dr Read", + 0x30 | 0x31 | 0x32 | 0x33 | 0x34 | 0x35 | 0x36 | 0x37 | 0x38 | 0x39 | 0x3a | 0x3b | 0x3c | 0x3d | 0x3e | 0x3f => "Dr Wirte", + 0x40 | 0x41 | 0x42 | 0x43 | 0x44 | 0x45 | 0x46 | 0x47 | 0x48 | 0x49 | 0x4a | 0x4b | 0x4c | 0x4d | 0x4e | 0x4f => "Exception", + 0x50 | 0x51 | 0x52 | 0x53 | 0x54 | 0x55 | 0x56 | 0x57 | 0x58 | 0x59 | 0x5a | 0x5b | 0x5c | 0x5d | 0x5e | 0x5f => "Exception", + 0x60 => "Physical INTR", + 0x61 => "Physical NMI", + 0x62 => "Physical SMI (the EXITINFO1 field provides more information)", + 0x63 => "Physical INIT", + 0x64 => "Virtual INTR", + 0x65 => "Write of CR0 changed bits other than CR0. TS or CR0.MP.", + 0x66 => "Read of IDTR", + 0x67 => "Read of GDTR", + 0x68 => "Read of LDTR", + 0x69 => "Read of TR", + 0x6a => "Write of IDTR", + 0x6b => "Write of GDTR", + 0x6c => "Write of LDTR", + 0x6d => "Write of TR", + 0x6e => "RDTSC instruction", + 0x6f => "RDTSCP instruction", + 0x70 => "Pushf instruction", + 0x71 => "Popf instruction", + 0x72 => "CPUID instruction", + 0x73 => "RSM instruction", + 0x74 => "IRET instruction", + 0x75 => "Software interrupt (INTn instruction)", + 0x76 => "INVD instruction", + 0x77 => "PAUSE instruction", + 0x78 => "HLT instruction", + 0x79 => "INVLPG instruction", + 0x7a => "INVLPGA instruction", + 0x7b => "IN or OOUT accessing protected port (the EXITINF1 field provides more information)", + 0x7c => "RDMSR or WRMSR access to protexted MSR", + 0x7d => "Task switch", + 0x7e => "FP legacy handling enabled, and processor is frozen in x87/mmx instruction waiting for an interrupt", + 0x7f => "Shutdown", + 0x80 => "VMRUN instruction", + 0x81 => "VMMCALL instruction", + 0x82 => "VMLOAD instruction", + 0x83 => "VMSAVE instruction", + 0x84 => "STGI instruction", + 0x85 => "CLGI instruction", + 0x86 => "SKINIT instruction", + 0x87 => "RDTSCP instruction", + 0x88 => "ICEBP instruction", + 0x89 => "WBINVD or WBNINVD instruction", + 0x8a => "MONITOR or MONITORX instruction", + 0x8b => "MWAIT or MWAITX instruction", + 0x8c => "MWAIT or MWAITX instruction, if monitor handware is armed", + 0x8d => "XSETBV instruction", + 0x8e => "RDPRU instruction", + 0x8f => "EFER write trap (occurs after guest instruction is finishes)", + 0x90 | 0x91 | 0x92 | 0x93 | 0x94 | 0x95 | 0x96 | 0x97 | 0x98 | 0x99 | 0x9a | 0x9b | 0x9c | 0x9d | 0x9e | 0x9f => "Write of CR0-15, respectively (occurs after guest instruction is finishes)", + 0xa0 => "INVLPGB instruction", + 0xa1 => "Illegal INVLPGB instruction", + 0xa2 => "INVOCID instruction", + 0xa3 => "MCOMMIT instruction", + 0xa4 => "TLBSYNC instruction", + 0xa5 => "Bus lock while Bus Lock Threshold Counter value is 0.", + 0xa6 => "HLT instructio if a virtual interrupt is not pending", + 0x400 => "Nested paging: host-level page fault occurred (EXITINFO1 contains fault error code; EXITINFO2 contains the guest physical address causing the fault).", + 0x401 => "AVIC—Virtual IPI delivery not completed. See \"AVIC IPI Delivery Not Completed\" on page 580 for EXITINFO1–2 definitions.", + 0x402 => "AVIC—Attempted access by guest to vAPIC register not handled by AVIC hardware. See \"AVIC Access to Unaccelerated vAPIC register\" on page 581 for EXITINFO1–2 definitions.", + 0x403 => "VMGEXIT instruction", + 0xF000_000 => "Reserved for Host", + -1 => "Invalid guest state in VMCB.", + -2 => "BUSY bit was set in the VMSA", + -3 => "The sibling thread is not in an idle state", + -4 => "Invalid PMC state", + _ => "[INVALID]", + } + } +} + +impl From for SvmInstructionError { + fn from(value: i32) -> Self { + Self(value) + } +} + +impl Debug for SvmInstructionError { + fn fmt(&self, f: &mut Formatter) -> Result { + write!(f, "SvmInstructionError({}, {:?})", self.0, self.as_str()) + } +} + +numeric_enum_macro::numeric_enum! { +#[repr(i32)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[allow(non_camel_case_types)] +pub enum SvmExitReason { + Cr0Read = 0x0, + Cr1Read = 0x1, + Cr2Read = 0x2, + Cr3Read = 0x3, + Cr4Read = 0x4, + Cr5Read = 0x5, + Cr6Read = 0x6, + Cr7Read = 0x7, + Cr8Read = 0x8, + Cr9Read = 0x9, + Cr10Read = 0xa, + Cr11Read = 0xb, + Cr12Read = 0xc, + Cr13Read = 0xd, + Cr14Read = 0xe, + Cr15Read = 0xf, + Cr0Write = 0x10, + Cr1Write = 0x11, + Cr2Write = 0x12, + Cr3Write = 0x13, + Cr4Write = 0x14, + Cr5Write = 0x15, + Cr6Write = 0x16, + Cr7Write = 0x17, + Cr8Write = 0x18, + Cr9Write = 0x19, + Cr10Write = 0x1a, + Cr11Write = 0x1b, + Cr12Write = 0x1c, + Cr13Write = 0x1d, + Cr14Write = 0x1e, + Cr15Write = 0x1f, + Dr0Read = 0x20, + Dr1Read = 0x21, + Dr2Read = 0x22, + Dr3Read = 0x23, + Dr4Read = 0x24, + Dr5Read = 0x25, + Dr6Read = 0x26, + Dr7Read = 0x27, + Dr8Read = 0x28, + Dr9Read = 0x29, + Dr10Read = 0x2a, + Dr11Read = 0x2b, + Dr12Read = 0x2c, + Dr13Read = 0x2d, + Dr14Read = 0x2e, + Dr15Read = 0x2f, + Dr0Write = 0x30, + Dr1Write = 0x31, + Dr2Write = 0x32, + Dr3Write = 0x33, + Dr4Write = 0x34, + Dr5Write = 0x35, + Dr6Write = 0x36, + Dr7Write = 0x37, + Dr8Write = 0x38, + Dr9Write = 0x39, + Dr10Write = 0x3a, + Dr11Write = 0x3b, + Dr12Write = 0x3c, + Dr13Write = 0x3d, + Dr14Write = 0x3e, + Dr15Write = 0x3f, + Excp_0 = 0x40, + Excp_1 = 0x41, + Excp_2 = 0x42, + Excp_3 = 0x43, + Excp_4 = 0x44, + Excp_5 = 0x45, + Excp_6 = 0x46, + Excp_7 = 0x47, + Excp_8 = 0x48, + Excp_9 = 0x49, + Excp_10 = 0x4a, + Excp_11 = 0x4b, + Excp_12 = 0x4c, + Excp_13 = 0x4d, + Excp_14 = 0x4e, + Excp_15 = 0x4f, + Excp_16 = 0x50, + Excp_17 = 0x51, + Excp_18 = 0x52, + Excp_19 = 0x53, + Excp_20 = 0x54, + Excp_21 = 0x55, + Excp_22 = 0x56, + Excp_23 = 0x57, + Excp_24 = 0x58, + Excp_25 = 0x59, + Excp_26 = 0x5a, + Excp_27 = 0x5b, + Excp_28 = 0x5c, + Excp_29 = 0x5d, + Excp_30 = 0x5e, + Excp_31 = 0x5f, + + Intr = 0x60, + Nmi = 0x61, + Smi = 0x62, + Init = 0x63, + Vintr = 0x64, + Cr0SelWrite = 0x65, + IdtrRead = 0x66, + GdtrRead = 0x67, + LdtrRead = 0x68, + TrRead = 0x69, + IdtrWrite = 0x6a, + GdtrWrite = 0x6b, + LdtrWrite = 0x6c, + TrWrite = 0x6d, + Rdtsc = 0x6e, + Rdpmc = 0x6f, + Pushf = 0x70, + Popf = 0x71, + Cpuid = 0x72, + Rsm = 0x73, + Iret = 0x74, + Swint = 0x75, + Invd = 0x76, + Pause = 0x77, + Hlt = 0x78, + Invlpg = 0x79, + Invlpga = 0x7a, + Ioio = 0x7b, + Msr = 0x7c, + TaskSwitch = 0x7d, + FreeFreeze = 0x7e, + Shutdown = 0x7f, + Vmrun = 0x80, + Vmmcall = 0x81, + Vmload = 0x82, + Vmsave = 0x83, + Stgi = 0x84, + Clgi = 0x85, + Skinit = 0x86, + Rdtscp = 0x87, + Icebp = 0x88, + Wbinvd = 0x89, + Monitor = 0x8a, + Mwait = 0x8b, + MwaitConditioal = 0x8c, + Xsetbv = 0x8d, + Rdpru = 0x8e, + EferWriteTrap = 0x8f, + + Cr0WriteTrap = 0x90, + Cr1WriteTrap = 0x91, + Cr2WriteTrap = 0x92, + Cr3WriteTrap = 0x93, + Cr4WriteTrap = 0x94, + Cr5WriteTrap = 0x95, + Cr6WriteTrap = 0x96, + Cr7WriteTrap = 0x97, + Cr8WriteTrap = 0x98, + Cr9WriteTrap = 0x99, + Cr10WriteTrap = 0x9a, + Cr11WriteTrap = 0x9b, + Cr12WriteTrap = 0x9c, + Cr13WriteTrap = 0x9d, + Cr14WriteTrap = 0x9e, + Cr15WriteTrap = 0x9f, + + Invlpgb = 0xa0, + InvlpgaIllegal = 0xa1, + Invpcid = 0xa2, + Mcommit = 0xa3, + Tlbsync = 0xa4, + Buslock = 0xa5, + IdleHlt = 0xa6, + + Npf = 0x400, + AvicIncompleteIpi = 0x401, + AvicNoaccel = 0x402, + Vmgexit = 0x403, + + Invalid = -1, + Busy = -2, + IdleRequired = -3, + InvalidPmc = -4, +} +} + +#[derive(Debug)] +pub struct SvmExitInfo { + pub entry_failure: bool, + pub exit_reason: SvmExitReason, + pub exit_instruction_length: u32, + pub guest_rip: usize, +}