|  | /* 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]; | 
|  |  | 
|  | u64 ssp; | 
|  | /* svm_* fields below are not implemented by KVM */ | 
|  | 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) | 
|  | { | 
|  | if (!kvm_x86_call(has_emulated_msr)(vcpu->kvm, MSR_IA32_SMBASE)) | 
|  | return -ENOTTY; | 
|  |  | 
|  | 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 |