0023-KVM-x86-smm-add-structs-for-KVM-s-smram-layout.patch 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. From dae1d13d62cdc44a137c51fbc92c5037a8f104c5 Mon Sep 17 00:00:00 2001
  2. From: Maxim Levitsky <[email protected]>
  3. Date: Tue, 25 Oct 2022 15:47:34 +0300
  4. Subject: [PATCH] KVM: x86: smm: add structs for KVM's smram layout
  5. Add structs that will be used to define and read/write the KVM's
  6. SMRAM layout, instead of reading/writing to raw offsets.
  7. Also document the differences between KVM's SMRAM layout and SMRAM
  8. layout that is used by real Intel/AMD cpus.
  9. Signed-off-by: Maxim Levitsky <[email protected]>
  10. ---
  11. arch/x86/kvm/smm.c | 94 +++++++++++++++++++++++++++++++++
  12. arch/x86/kvm/smm.h | 127 +++++++++++++++++++++++++++++++++++++++++++++
  13. 2 files changed, 221 insertions(+)
  14. diff --git a/arch/x86/kvm/smm.c b/arch/x86/kvm/smm.c
  15. index 1191a79cf027..01dab9fc3ab4 100644
  16. --- a/arch/x86/kvm/smm.c
  17. +++ b/arch/x86/kvm/smm.c
  18. @@ -8,6 +8,97 @@
  19. #include "cpuid.h"
  20. #include "trace.h"
  21. +#define CHECK_SMRAM32_OFFSET(field, offset) \
  22. + ASSERT_STRUCT_OFFSET(struct kvm_smram_state_32, field, offset - 0xFE00)
  23. +
  24. +#define CHECK_SMRAM64_OFFSET(field, offset) \
  25. + ASSERT_STRUCT_OFFSET(struct kvm_smram_state_64, field, offset - 0xFE00)
  26. +
  27. +static void check_smram_offsets(void)
  28. +{
  29. + /* 32 bit SMRAM image */
  30. + CHECK_SMRAM32_OFFSET(reserved1, 0xFE00);
  31. + CHECK_SMRAM32_OFFSET(smbase, 0xFEF8);
  32. + CHECK_SMRAM32_OFFSET(smm_revision, 0xFEFC);
  33. + CHECK_SMRAM32_OFFSET(reserved2, 0xFF00);
  34. + CHECK_SMRAM32_OFFSET(cr4, 0xFF14);
  35. + CHECK_SMRAM32_OFFSET(reserved3, 0xFF18);
  36. + CHECK_SMRAM32_OFFSET(ds, 0xFF2C);
  37. + CHECK_SMRAM32_OFFSET(fs, 0xFF38);
  38. + CHECK_SMRAM32_OFFSET(gs, 0xFF44);
  39. + CHECK_SMRAM32_OFFSET(idtr, 0xFF50);
  40. + CHECK_SMRAM32_OFFSET(tr, 0xFF5C);
  41. + CHECK_SMRAM32_OFFSET(gdtr, 0xFF6C);
  42. + CHECK_SMRAM32_OFFSET(ldtr, 0xFF78);
  43. + CHECK_SMRAM32_OFFSET(es, 0xFF84);
  44. + CHECK_SMRAM32_OFFSET(cs, 0xFF90);
  45. + CHECK_SMRAM32_OFFSET(ss, 0xFF9C);
  46. + CHECK_SMRAM32_OFFSET(es_sel, 0xFFA8);
  47. + CHECK_SMRAM32_OFFSET(cs_sel, 0xFFAC);
  48. + CHECK_SMRAM32_OFFSET(ss_sel, 0xFFB0);
  49. + CHECK_SMRAM32_OFFSET(ds_sel, 0xFFB4);
  50. + CHECK_SMRAM32_OFFSET(fs_sel, 0xFFB8);
  51. + CHECK_SMRAM32_OFFSET(gs_sel, 0xFFBC);
  52. + CHECK_SMRAM32_OFFSET(ldtr_sel, 0xFFC0);
  53. + CHECK_SMRAM32_OFFSET(tr_sel, 0xFFC4);
  54. + CHECK_SMRAM32_OFFSET(dr7, 0xFFC8);
  55. + CHECK_SMRAM32_OFFSET(dr6, 0xFFCC);
  56. + CHECK_SMRAM32_OFFSET(gprs, 0xFFD0);
  57. + CHECK_SMRAM32_OFFSET(eip, 0xFFF0);
  58. + CHECK_SMRAM32_OFFSET(eflags, 0xFFF4);
  59. + CHECK_SMRAM32_OFFSET(cr3, 0xFFF8);
  60. + CHECK_SMRAM32_OFFSET(cr0, 0xFFFC);
  61. +
  62. + /* 64 bit SMRAM image */
  63. + CHECK_SMRAM64_OFFSET(es, 0xFE00);
  64. + CHECK_SMRAM64_OFFSET(cs, 0xFE10);
  65. + CHECK_SMRAM64_OFFSET(ss, 0xFE20);
  66. + CHECK_SMRAM64_OFFSET(ds, 0xFE30);
  67. + CHECK_SMRAM64_OFFSET(fs, 0xFE40);
  68. + CHECK_SMRAM64_OFFSET(gs, 0xFE50);
  69. + CHECK_SMRAM64_OFFSET(gdtr, 0xFE60);
  70. + CHECK_SMRAM64_OFFSET(ldtr, 0xFE70);
  71. + CHECK_SMRAM64_OFFSET(idtr, 0xFE80);
  72. + CHECK_SMRAM64_OFFSET(tr, 0xFE90);
  73. + CHECK_SMRAM64_OFFSET(io_restart_rip, 0xFEA0);
  74. + CHECK_SMRAM64_OFFSET(io_restart_rcx, 0xFEA8);
  75. + CHECK_SMRAM64_OFFSET(io_restart_rsi, 0xFEB0);
  76. + CHECK_SMRAM64_OFFSET(io_restart_rdi, 0xFEB8);
  77. + CHECK_SMRAM64_OFFSET(io_restart_dword, 0xFEC0);
  78. + CHECK_SMRAM64_OFFSET(reserved1, 0xFEC4);
  79. + CHECK_SMRAM64_OFFSET(io_inst_restart, 0xFEC8);
  80. + CHECK_SMRAM64_OFFSET(auto_hlt_restart, 0xFEC9);
  81. + CHECK_SMRAM64_OFFSET(reserved2, 0xFECA);
  82. + CHECK_SMRAM64_OFFSET(efer, 0xFED0);
  83. + CHECK_SMRAM64_OFFSET(svm_guest_flag, 0xFED8);
  84. + CHECK_SMRAM64_OFFSET(svm_guest_vmcb_gpa, 0xFEE0);
  85. + CHECK_SMRAM64_OFFSET(svm_guest_virtual_int, 0xFEE8);
  86. + CHECK_SMRAM64_OFFSET(reserved3, 0xFEF0);
  87. + CHECK_SMRAM64_OFFSET(smm_revison, 0xFEFC);
  88. + CHECK_SMRAM64_OFFSET(smbase, 0xFF00);
  89. + CHECK_SMRAM64_OFFSET(reserved4, 0xFF04);
  90. + CHECK_SMRAM64_OFFSET(ssp, 0xFF18);
  91. + CHECK_SMRAM64_OFFSET(svm_guest_pat, 0xFF20);
  92. + CHECK_SMRAM64_OFFSET(svm_host_efer, 0xFF28);
  93. + CHECK_SMRAM64_OFFSET(svm_host_cr4, 0xFF30);
  94. + CHECK_SMRAM64_OFFSET(svm_host_cr3, 0xFF38);
  95. + CHECK_SMRAM64_OFFSET(svm_host_cr0, 0xFF40);
  96. + CHECK_SMRAM64_OFFSET(cr4, 0xFF48);
  97. + CHECK_SMRAM64_OFFSET(cr3, 0xFF50);
  98. + CHECK_SMRAM64_OFFSET(cr0, 0xFF58);
  99. + CHECK_SMRAM64_OFFSET(dr7, 0xFF60);
  100. + CHECK_SMRAM64_OFFSET(dr6, 0xFF68);
  101. + CHECK_SMRAM64_OFFSET(rflags, 0xFF70);
  102. + CHECK_SMRAM64_OFFSET(rip, 0xFF78);
  103. + CHECK_SMRAM64_OFFSET(gprs, 0xFF80);
  104. +
  105. + BUILD_BUG_ON(sizeof(union kvm_smram) != 512);
  106. +}
  107. +
  108. +#undef CHECK_SMRAM64_OFFSET
  109. +#undef CHECK_SMRAM32_OFFSET
  110. +
  111. +
  112. void kvm_smm_changed(struct kvm_vcpu *vcpu, bool entering_smm)
  113. {
  114. trace_kvm_smm_transition(vcpu->vcpu_id, vcpu->arch.smbase, entering_smm);
  115. @@ -199,6 +290,8 @@ void enter_smm(struct kvm_vcpu *vcpu)
  116. unsigned long cr0;
  117. char buf[512];
  118. + check_smram_offsets();
  119. +
  120. memset(buf, 0, 512);
  121. #ifdef CONFIG_X86_64
  122. if (guest_cpuid_has(vcpu, X86_FEATURE_LM))
  123. @@ -449,6 +542,7 @@ static int rsm_load_state_64(struct x86_emulate_ctxt *ctxt,
  124. u64 val, cr0, cr3, cr4;
  125. int i, r;
  126. +
  127. for (i = 0; i < 16; i++)
  128. *reg_write(ctxt, i) = GET_SMSTATE(u64, smstate, 0x7ff8 - i * 8);
  129. diff --git a/arch/x86/kvm/smm.h b/arch/x86/kvm/smm.h
  130. index a6795b93ba30..bf5c7ffeb11e 100644
  131. --- a/arch/x86/kvm/smm.h
  132. +++ b/arch/x86/kvm/smm.h
  133. @@ -2,6 +2,8 @@
  134. #ifndef ASM_KVM_SMM_H
  135. #define ASM_KVM_SMM_H
  136. +#include <linux/build_bug.h>
  137. +
  138. #define GET_SMSTATE(type, buf, offset) \
  139. (*(type *)((buf) + (offset) - 0x7e00))
  140. @@ -9,6 +11,131 @@
  141. *(type *)((buf) + (offset) - 0x7e00) = val
  142. #ifdef CONFIG_KVM_SMM
  143. +
  144. +
  145. +/* 32 bit KVM's emulated SMM layout. Loosely based on Intel's layout */
  146. +
  147. +struct kvm_smm_seg_state_32 {
  148. + u32 flags;
  149. + u32 limit;
  150. + u32 base;
  151. +} __packed;
  152. +
  153. +struct kvm_smram_state_32 {
  154. + u32 reserved1[62];
  155. + u32 smbase;
  156. + u32 smm_revision;
  157. + u32 reserved2[5];
  158. + u32 cr4; /* CR4 is not present in Intel/AMD SMRAM image */
  159. + u32 reserved3[5];
  160. +
  161. + /*
  162. + * Segment state is not present/documented in the Intel/AMD SMRAM image
  163. + * Instead this area on Intel/AMD contains IO/HLT restart flags.
  164. + */
  165. + struct kvm_smm_seg_state_32 ds;
  166. + struct kvm_smm_seg_state_32 fs;
  167. + struct kvm_smm_seg_state_32 gs;
  168. + struct kvm_smm_seg_state_32 idtr; /* IDTR has only base and limit */
  169. + struct kvm_smm_seg_state_32 tr;
  170. + u32 reserved;
  171. + struct kvm_smm_seg_state_32 gdtr; /* GDTR has only base and limit */
  172. + struct kvm_smm_seg_state_32 ldtr;
  173. + struct kvm_smm_seg_state_32 es;
  174. + struct kvm_smm_seg_state_32 cs;
  175. + struct kvm_smm_seg_state_32 ss;
  176. +
  177. + u32 es_sel;
  178. + u32 cs_sel;
  179. + u32 ss_sel;
  180. + u32 ds_sel;
  181. + u32 fs_sel;
  182. + u32 gs_sel;
  183. + u32 ldtr_sel;
  184. + u32 tr_sel;
  185. +
  186. + u32 dr7;
  187. + u32 dr6;
  188. + u32 gprs[8]; /* GPRS in the "natural" X86 order (EAX/ECX/EDX.../EDI) */
  189. + u32 eip;
  190. + u32 eflags;
  191. + u32 cr3;
  192. + u32 cr0;
  193. +} __packed;
  194. +
  195. +
  196. +/* 64 bit KVM's emulated SMM layout. Based on AMD64 layout */
  197. +
  198. +struct kvm_smm_seg_state_64 {
  199. + u16 selector;
  200. + u16 attributes;
  201. + u32 limit;
  202. + u64 base;
  203. +};
  204. +
  205. +struct kvm_smram_state_64 {
  206. +
  207. + struct kvm_smm_seg_state_64 es;
  208. + struct kvm_smm_seg_state_64 cs;
  209. + struct kvm_smm_seg_state_64 ss;
  210. + struct kvm_smm_seg_state_64 ds;
  211. + struct kvm_smm_seg_state_64 fs;
  212. + struct kvm_smm_seg_state_64 gs;
  213. + struct kvm_smm_seg_state_64 gdtr; /* GDTR has only base and limit*/
  214. + struct kvm_smm_seg_state_64 ldtr;
  215. + struct kvm_smm_seg_state_64 idtr; /* IDTR has only base and limit*/
  216. + struct kvm_smm_seg_state_64 tr;
  217. +
  218. + /* I/O restart and auto halt restart are not implemented by KVM */
  219. + u64 io_restart_rip;
  220. + u64 io_restart_rcx;
  221. + u64 io_restart_rsi;
  222. + u64 io_restart_rdi;
  223. + u32 io_restart_dword;
  224. + u32 reserved1;
  225. + u8 io_inst_restart;
  226. + u8 auto_hlt_restart;
  227. + u8 reserved2[6];
  228. +
  229. + u64 efer;
  230. +
  231. + /*
  232. + * Two fields below are implemented on AMD only, to store
  233. + * SVM guest vmcb address if the #SMI was received while in the guest mode.
  234. + */
  235. + u64 svm_guest_flag;
  236. + u64 svm_guest_vmcb_gpa;
  237. + u64 svm_guest_virtual_int; /* unknown purpose, not implemented */
  238. +
  239. + u32 reserved3[3];
  240. + u32 smm_revison;
  241. + u32 smbase;
  242. + u32 reserved4[5];
  243. +
  244. + /* ssp and svm_* fields below are not implemented by KVM */
  245. + u64 ssp;
  246. + u64 svm_guest_pat;
  247. + u64 svm_host_efer;
  248. + u64 svm_host_cr4;
  249. + u64 svm_host_cr3;
  250. + u64 svm_host_cr0;
  251. +
  252. + u64 cr4;
  253. + u64 cr3;
  254. + u64 cr0;
  255. + u64 dr7;
  256. + u64 dr6;
  257. + u64 rflags;
  258. + u64 rip;
  259. + u64 gprs[16]; /* GPRS in a reversed "natural" X86 order (R15/R14/../RCX/RAX.) */
  260. +};
  261. +
  262. +union kvm_smram {
  263. + struct kvm_smram_state_64 smram64;
  264. + struct kvm_smram_state_32 smram32;
  265. + u8 bytes[512];
  266. +};
  267. +
  268. static inline int kvm_inject_smi(struct kvm_vcpu *vcpu)
  269. {
  270. kvm_make_request(KVM_REQ_SMI, vcpu);
  271. --
  272. 2.38.1