| /* SPDX-License-Identifier: GPL-2.0 */ |
| #ifndef ASM_KVM_SMM_H |
| #define ASM_KVM_SMM_H |
| |
| #include <linux/build_bug.h> |
| |
| #ifdef CONFIG_KVM_SMM |
| |
| |
| /* |
| * 32 bit KVM's emulated SMM layout. Based on Intel P6 layout |
| * (https://www.sandpile.org/x86/smm.htm). |
| */ |
| |
| struct kvm_smm_seg_state_32 { |
| u32 flags; |
| u32 limit; |
| u32 base; |
| } __packed; |
| |
| struct kvm_smram_state_32 { |
| u32 reserved1[62]; |
| u32 smbase; |
| u32 smm_revision; |
| u16 io_inst_restart; |
| u16 auto_hlt_restart; |
| u32 io_restart_rdi; |
| u32 io_restart_rcx; |
| u32 io_restart_rsi; |
| u32 io_restart_rip; |
| u32 cr4; |
| |
| /* A20M#, CPL, shutdown and other reserved/undocumented fields */ |
| u16 reserved2; |
| u8 int_shadow; /* KVM extension */ |
| u8 reserved3[17]; |
| |
| struct kvm_smm_seg_state_32 ds; |
| struct kvm_smm_seg_state_32 fs; |
| struct kvm_smm_seg_state_32 gs; |
| struct kvm_smm_seg_state_32 idtr; /* IDTR has only base and limit */ |
| struct kvm_smm_seg_state_32 tr; |
| u32 reserved; |
| struct kvm_smm_seg_state_32 gdtr; /* GDTR has only base and limit */ |
| struct kvm_smm_seg_state_32 ldtr; |
| struct kvm_smm_seg_state_32 es; |
| struct kvm_smm_seg_state_32 cs; |
| struct kvm_smm_seg_state_32 ss; |
| |
| u32 es_sel; |
| u32 cs_sel; |
| u32 ss_sel; |
| u32 ds_sel; |
| u32 fs_sel; |
| u32 gs_sel; |
| u32 ldtr_sel; |
| u32 tr_sel; |
| |
| u32 dr7; |
| u32 dr6; |
| u32 gprs[8]; /* GPRS in the "natural" X86 order (EAX/ECX/EDX.../EDI) */ |
| u32 eip; |
| u32 eflags; |
| u32 cr3; |
| u32 cr0; |
| } __packed; |
| |
| |
| /* 64 bit KVM's emulated SMM layout. Based on AMD64 layout */ |
| |
| struct kvm_smm_seg_state_64 { |
| u16 selector; |
| u16 attributes; |
| u32 limit; |
| u64 base; |
| }; |
| |
| struct kvm_smram_state_64 { |
| |
| struct kvm_smm_seg_state_64 es; |
| struct kvm_smm_seg_state_64 cs; |
| struct kvm_smm_seg_state_64 ss; |
| struct kvm_smm_seg_state_64 ds; |
| struct kvm_smm_seg_state_64 fs; |
| struct kvm_smm_seg_state_64 gs; |
| struct kvm_smm_seg_state_64 gdtr; /* GDTR has only base and limit*/ |
| struct kvm_smm_seg_state_64 ldtr; |
| struct kvm_smm_seg_state_64 idtr; /* IDTR has only base and limit*/ |
| struct kvm_smm_seg_state_64 tr; |
| |
| /* I/O restart and auto halt restart are not implemented by KVM */ |
| u64 io_restart_rip; |
| u64 io_restart_rcx; |
| u64 io_restart_rsi; |
| u64 io_restart_rdi; |
| u32 io_restart_dword; |
| u32 reserved1; |
| u8 io_inst_restart; |
| u8 auto_hlt_restart; |
| u8 amd_nmi_mask; /* Documented in AMD BKDG as NMI mask, not used by KVM */ |
| u8 int_shadow; |
| u32 reserved2; |
| |
| u64 efer; |
| |
| /* |
| * Two fields below are implemented on AMD only, to store |
| * SVM guest vmcb address if the #SMI was received while in the guest mode. |
| */ |
| u64 svm_guest_flag; |
| u64 svm_guest_vmcb_gpa; |
| u64 svm_guest_virtual_int; /* unknown purpose, not implemented */ |
| |
| u32 reserved3[3]; |
| u32 smm_revison; |
| u32 smbase; |
| u32 reserved4[5]; |
| |
| /* ssp and svm_* fields below are not implemented by KVM */ |
| u64 ssp; |
| u64 svm_guest_pat; |
| u64 svm_host_efer; |
| u64 svm_host_cr4; |
| u64 svm_host_cr3; |
| u64 svm_host_cr0; |
| |
| u64 cr4; |
| u64 cr3; |
| u64 cr0; |
| u64 dr7; |
| u64 dr6; |
| u64 rflags; |
| u64 rip; |
| u64 gprs[16]; /* GPRS in a reversed "natural" X86 order (R15/R14/../RCX/RAX.) */ |
| }; |
| |
| union kvm_smram { |
| struct kvm_smram_state_64 smram64; |
| struct kvm_smram_state_32 smram32; |
| u8 bytes[512]; |
| }; |
| |
| static inline int kvm_inject_smi(struct kvm_vcpu *vcpu) |
| { |
| kvm_make_request(KVM_REQ_SMI, vcpu); |
| return 0; |
| } |
| |
| static inline bool is_smm(struct kvm_vcpu *vcpu) |
| { |
| return vcpu->arch.hflags & HF_SMM_MASK; |
| } |
| |
| void kvm_smm_changed(struct kvm_vcpu *vcpu, bool in_smm); |
| void enter_smm(struct kvm_vcpu *vcpu); |
| int emulator_leave_smm(struct x86_emulate_ctxt *ctxt); |
| void process_smi(struct kvm_vcpu *vcpu); |
| #else |
| static inline int kvm_inject_smi(struct kvm_vcpu *vcpu) { return -ENOTTY; } |
| static inline bool is_smm(struct kvm_vcpu *vcpu) { return false; } |
| |
| /* |
| * emulator_leave_smm is used as a function pointer, so the |
| * stub is defined in x86.c. |
| */ |
| #endif |
| |
| #endif |