xref: /linux/arch/x86/kvm/smm.h (revision ae22a94997b8a03dcb3c922857c203246711f9d4)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef ASM_KVM_SMM_H
3 #define ASM_KVM_SMM_H
4 
5 #include <linux/build_bug.h>
6 
7 #ifdef CONFIG_KVM_SMM
8 
9 
10 /*
11  * 32 bit KVM's emulated SMM layout. Based on Intel P6 layout
12  * (https://www.sandpile.org/x86/smm.htm).
13  */
14 
15 struct kvm_smm_seg_state_32 {
16 	u32 flags;
17 	u32 limit;
18 	u32 base;
19 } __packed;
20 
21 struct kvm_smram_state_32 {
22 	u32 reserved1[62];
23 	u32 smbase;
24 	u32 smm_revision;
25 	u16 io_inst_restart;
26 	u16 auto_hlt_restart;
27 	u32 io_restart_rdi;
28 	u32 io_restart_rcx;
29 	u32 io_restart_rsi;
30 	u32 io_restart_rip;
31 	u32 cr4;
32 
33 	/* A20M#, CPL, shutdown and other reserved/undocumented fields */
34 	u16 reserved2;
35 	u8 int_shadow; /* KVM extension */
36 	u8 reserved3[17];
37 
38 	struct kvm_smm_seg_state_32 ds;
39 	struct kvm_smm_seg_state_32 fs;
40 	struct kvm_smm_seg_state_32 gs;
41 	struct kvm_smm_seg_state_32 idtr; /* IDTR has only base and limit */
42 	struct kvm_smm_seg_state_32 tr;
43 	u32 reserved;
44 	struct kvm_smm_seg_state_32 gdtr; /* GDTR has only base and limit */
45 	struct kvm_smm_seg_state_32 ldtr;
46 	struct kvm_smm_seg_state_32 es;
47 	struct kvm_smm_seg_state_32 cs;
48 	struct kvm_smm_seg_state_32 ss;
49 
50 	u32 es_sel;
51 	u32 cs_sel;
52 	u32 ss_sel;
53 	u32 ds_sel;
54 	u32 fs_sel;
55 	u32 gs_sel;
56 	u32 ldtr_sel;
57 	u32 tr_sel;
58 
59 	u32 dr7;
60 	u32 dr6;
61 	u32 gprs[8]; /* GPRS in the "natural" X86 order (EAX/ECX/EDX.../EDI) */
62 	u32 eip;
63 	u32 eflags;
64 	u32 cr3;
65 	u32 cr0;
66 } __packed;
67 
68 
69 /* 64 bit KVM's emulated SMM layout. Based on AMD64 layout */
70 
71 struct kvm_smm_seg_state_64 {
72 	u16 selector;
73 	u16 attributes;
74 	u32 limit;
75 	u64 base;
76 };
77 
78 struct kvm_smram_state_64 {
79 
80 	struct kvm_smm_seg_state_64 es;
81 	struct kvm_smm_seg_state_64 cs;
82 	struct kvm_smm_seg_state_64 ss;
83 	struct kvm_smm_seg_state_64 ds;
84 	struct kvm_smm_seg_state_64 fs;
85 	struct kvm_smm_seg_state_64 gs;
86 	struct kvm_smm_seg_state_64 gdtr; /* GDTR has only base and limit*/
87 	struct kvm_smm_seg_state_64 ldtr;
88 	struct kvm_smm_seg_state_64 idtr; /* IDTR has only base and limit*/
89 	struct kvm_smm_seg_state_64 tr;
90 
91 	/* I/O restart and auto halt restart are not implemented by KVM */
92 	u64 io_restart_rip;
93 	u64 io_restart_rcx;
94 	u64 io_restart_rsi;
95 	u64 io_restart_rdi;
96 	u32 io_restart_dword;
97 	u32 reserved1;
98 	u8 io_inst_restart;
99 	u8 auto_hlt_restart;
100 	u8 amd_nmi_mask; /* Documented in AMD BKDG as NMI mask, not used by KVM */
101 	u8 int_shadow;
102 	u32 reserved2;
103 
104 	u64 efer;
105 
106 	/*
107 	 * Two fields below are implemented on AMD only, to store
108 	 * SVM guest vmcb address if the #SMI was received while in the guest mode.
109 	 */
110 	u64 svm_guest_flag;
111 	u64 svm_guest_vmcb_gpa;
112 	u64 svm_guest_virtual_int; /* unknown purpose, not implemented */
113 
114 	u32 reserved3[3];
115 	u32 smm_revison;
116 	u32 smbase;
117 	u32 reserved4[5];
118 
119 	/* ssp and svm_* fields below are not implemented by KVM */
120 	u64 ssp;
121 	u64 svm_guest_pat;
122 	u64 svm_host_efer;
123 	u64 svm_host_cr4;
124 	u64 svm_host_cr3;
125 	u64 svm_host_cr0;
126 
127 	u64 cr4;
128 	u64 cr3;
129 	u64 cr0;
130 	u64 dr7;
131 	u64 dr6;
132 	u64 rflags;
133 	u64 rip;
134 	u64 gprs[16]; /* GPRS in a reversed "natural" X86 order (R15/R14/../RCX/RAX.) */
135 };
136 
137 union kvm_smram {
138 	struct kvm_smram_state_64 smram64;
139 	struct kvm_smram_state_32 smram32;
140 	u8 bytes[512];
141 };
142 
143 static inline int kvm_inject_smi(struct kvm_vcpu *vcpu)
144 {
145 	kvm_make_request(KVM_REQ_SMI, vcpu);
146 	return 0;
147 }
148 
149 static inline bool is_smm(struct kvm_vcpu *vcpu)
150 {
151 	return vcpu->arch.hflags & HF_SMM_MASK;
152 }
153 
154 void kvm_smm_changed(struct kvm_vcpu *vcpu, bool in_smm);
155 void enter_smm(struct kvm_vcpu *vcpu);
156 int emulator_leave_smm(struct x86_emulate_ctxt *ctxt);
157 void process_smi(struct kvm_vcpu *vcpu);
158 #else
159 static inline int kvm_inject_smi(struct kvm_vcpu *vcpu) { return -ENOTTY; }
160 static inline bool is_smm(struct kvm_vcpu *vcpu) { return false; }
161 
162 /*
163  * emulator_leave_smm is used as a function pointer, so the
164  * stub is defined in x86.c.
165  */
166 #endif
167 
168 #endif
169