162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci#ifndef ASM_KVM_SMM_H 362306a36Sopenharmony_ci#define ASM_KVM_SMM_H 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <linux/build_bug.h> 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#ifdef CONFIG_KVM_SMM 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci/* 1162306a36Sopenharmony_ci * 32 bit KVM's emulated SMM layout. Based on Intel P6 layout 1262306a36Sopenharmony_ci * (https://www.sandpile.org/x86/smm.htm). 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistruct kvm_smm_seg_state_32 { 1662306a36Sopenharmony_ci u32 flags; 1762306a36Sopenharmony_ci u32 limit; 1862306a36Sopenharmony_ci u32 base; 1962306a36Sopenharmony_ci} __packed; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistruct kvm_smram_state_32 { 2262306a36Sopenharmony_ci u32 reserved1[62]; 2362306a36Sopenharmony_ci u32 smbase; 2462306a36Sopenharmony_ci u32 smm_revision; 2562306a36Sopenharmony_ci u16 io_inst_restart; 2662306a36Sopenharmony_ci u16 auto_hlt_restart; 2762306a36Sopenharmony_ci u32 io_restart_rdi; 2862306a36Sopenharmony_ci u32 io_restart_rcx; 2962306a36Sopenharmony_ci u32 io_restart_rsi; 3062306a36Sopenharmony_ci u32 io_restart_rip; 3162306a36Sopenharmony_ci u32 cr4; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci /* A20M#, CPL, shutdown and other reserved/undocumented fields */ 3462306a36Sopenharmony_ci u16 reserved2; 3562306a36Sopenharmony_ci u8 int_shadow; /* KVM extension */ 3662306a36Sopenharmony_ci u8 reserved3[17]; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci struct kvm_smm_seg_state_32 ds; 3962306a36Sopenharmony_ci struct kvm_smm_seg_state_32 fs; 4062306a36Sopenharmony_ci struct kvm_smm_seg_state_32 gs; 4162306a36Sopenharmony_ci struct kvm_smm_seg_state_32 idtr; /* IDTR has only base and limit */ 4262306a36Sopenharmony_ci struct kvm_smm_seg_state_32 tr; 4362306a36Sopenharmony_ci u32 reserved; 4462306a36Sopenharmony_ci struct kvm_smm_seg_state_32 gdtr; /* GDTR has only base and limit */ 4562306a36Sopenharmony_ci struct kvm_smm_seg_state_32 ldtr; 4662306a36Sopenharmony_ci struct kvm_smm_seg_state_32 es; 4762306a36Sopenharmony_ci struct kvm_smm_seg_state_32 cs; 4862306a36Sopenharmony_ci struct kvm_smm_seg_state_32 ss; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci u32 es_sel; 5162306a36Sopenharmony_ci u32 cs_sel; 5262306a36Sopenharmony_ci u32 ss_sel; 5362306a36Sopenharmony_ci u32 ds_sel; 5462306a36Sopenharmony_ci u32 fs_sel; 5562306a36Sopenharmony_ci u32 gs_sel; 5662306a36Sopenharmony_ci u32 ldtr_sel; 5762306a36Sopenharmony_ci u32 tr_sel; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci u32 dr7; 6062306a36Sopenharmony_ci u32 dr6; 6162306a36Sopenharmony_ci u32 gprs[8]; /* GPRS in the "natural" X86 order (EAX/ECX/EDX.../EDI) */ 6262306a36Sopenharmony_ci u32 eip; 6362306a36Sopenharmony_ci u32 eflags; 6462306a36Sopenharmony_ci u32 cr3; 6562306a36Sopenharmony_ci u32 cr0; 6662306a36Sopenharmony_ci} __packed; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/* 64 bit KVM's emulated SMM layout. Based on AMD64 layout */ 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistruct kvm_smm_seg_state_64 { 7262306a36Sopenharmony_ci u16 selector; 7362306a36Sopenharmony_ci u16 attributes; 7462306a36Sopenharmony_ci u32 limit; 7562306a36Sopenharmony_ci u64 base; 7662306a36Sopenharmony_ci}; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistruct kvm_smram_state_64 { 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci struct kvm_smm_seg_state_64 es; 8162306a36Sopenharmony_ci struct kvm_smm_seg_state_64 cs; 8262306a36Sopenharmony_ci struct kvm_smm_seg_state_64 ss; 8362306a36Sopenharmony_ci struct kvm_smm_seg_state_64 ds; 8462306a36Sopenharmony_ci struct kvm_smm_seg_state_64 fs; 8562306a36Sopenharmony_ci struct kvm_smm_seg_state_64 gs; 8662306a36Sopenharmony_ci struct kvm_smm_seg_state_64 gdtr; /* GDTR has only base and limit*/ 8762306a36Sopenharmony_ci struct kvm_smm_seg_state_64 ldtr; 8862306a36Sopenharmony_ci struct kvm_smm_seg_state_64 idtr; /* IDTR has only base and limit*/ 8962306a36Sopenharmony_ci struct kvm_smm_seg_state_64 tr; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci /* I/O restart and auto halt restart are not implemented by KVM */ 9262306a36Sopenharmony_ci u64 io_restart_rip; 9362306a36Sopenharmony_ci u64 io_restart_rcx; 9462306a36Sopenharmony_ci u64 io_restart_rsi; 9562306a36Sopenharmony_ci u64 io_restart_rdi; 9662306a36Sopenharmony_ci u32 io_restart_dword; 9762306a36Sopenharmony_ci u32 reserved1; 9862306a36Sopenharmony_ci u8 io_inst_restart; 9962306a36Sopenharmony_ci u8 auto_hlt_restart; 10062306a36Sopenharmony_ci u8 amd_nmi_mask; /* Documented in AMD BKDG as NMI mask, not used by KVM */ 10162306a36Sopenharmony_ci u8 int_shadow; 10262306a36Sopenharmony_ci u32 reserved2; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci u64 efer; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci /* 10762306a36Sopenharmony_ci * Two fields below are implemented on AMD only, to store 10862306a36Sopenharmony_ci * SVM guest vmcb address if the #SMI was received while in the guest mode. 10962306a36Sopenharmony_ci */ 11062306a36Sopenharmony_ci u64 svm_guest_flag; 11162306a36Sopenharmony_ci u64 svm_guest_vmcb_gpa; 11262306a36Sopenharmony_ci u64 svm_guest_virtual_int; /* unknown purpose, not implemented */ 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci u32 reserved3[3]; 11562306a36Sopenharmony_ci u32 smm_revison; 11662306a36Sopenharmony_ci u32 smbase; 11762306a36Sopenharmony_ci u32 reserved4[5]; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci /* ssp and svm_* fields below are not implemented by KVM */ 12062306a36Sopenharmony_ci u64 ssp; 12162306a36Sopenharmony_ci u64 svm_guest_pat; 12262306a36Sopenharmony_ci u64 svm_host_efer; 12362306a36Sopenharmony_ci u64 svm_host_cr4; 12462306a36Sopenharmony_ci u64 svm_host_cr3; 12562306a36Sopenharmony_ci u64 svm_host_cr0; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci u64 cr4; 12862306a36Sopenharmony_ci u64 cr3; 12962306a36Sopenharmony_ci u64 cr0; 13062306a36Sopenharmony_ci u64 dr7; 13162306a36Sopenharmony_ci u64 dr6; 13262306a36Sopenharmony_ci u64 rflags; 13362306a36Sopenharmony_ci u64 rip; 13462306a36Sopenharmony_ci u64 gprs[16]; /* GPRS in a reversed "natural" X86 order (R15/R14/../RCX/RAX.) */ 13562306a36Sopenharmony_ci}; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ciunion kvm_smram { 13862306a36Sopenharmony_ci struct kvm_smram_state_64 smram64; 13962306a36Sopenharmony_ci struct kvm_smram_state_32 smram32; 14062306a36Sopenharmony_ci u8 bytes[512]; 14162306a36Sopenharmony_ci}; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic inline int kvm_inject_smi(struct kvm_vcpu *vcpu) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci kvm_make_request(KVM_REQ_SMI, vcpu); 14662306a36Sopenharmony_ci return 0; 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistatic inline bool is_smm(struct kvm_vcpu *vcpu) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci return vcpu->arch.hflags & HF_SMM_MASK; 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_civoid kvm_smm_changed(struct kvm_vcpu *vcpu, bool in_smm); 15562306a36Sopenharmony_civoid enter_smm(struct kvm_vcpu *vcpu); 15662306a36Sopenharmony_ciint emulator_leave_smm(struct x86_emulate_ctxt *ctxt); 15762306a36Sopenharmony_civoid process_smi(struct kvm_vcpu *vcpu); 15862306a36Sopenharmony_ci#else 15962306a36Sopenharmony_cistatic inline int kvm_inject_smi(struct kvm_vcpu *vcpu) { return -ENOTTY; } 16062306a36Sopenharmony_cistatic inline bool is_smm(struct kvm_vcpu *vcpu) { return false; } 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci/* 16362306a36Sopenharmony_ci * emulator_leave_smm is used as a function pointer, so the 16462306a36Sopenharmony_ci * stub is defined in x86.c. 16562306a36Sopenharmony_ci */ 16662306a36Sopenharmony_ci#endif 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci#endif 169