CcExitVcHandler.c 60 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355
  1. /** @file
  2. X64 #VC Exception Handler functon.
  3. Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include <Base.h>
  7. #include <Uefi.h>
  8. #include <Library/BaseMemoryLib.h>
  9. #include <Library/LocalApicLib.h>
  10. #include <Library/MemEncryptSevLib.h>
  11. #include <Library/CcExitLib.h>
  12. #include <Register/Amd/Msr.h>
  13. #include <Register/Intel/Cpuid.h>
  14. #include <IndustryStandard/InstructionParsing.h>
  15. #include "CcExitVcHandler.h"
  16. //
  17. // Instruction execution mode definition
  18. //
  19. typedef enum {
  20. LongMode64Bit = 0,
  21. LongModeCompat32Bit,
  22. LongModeCompat16Bit,
  23. } SEV_ES_INSTRUCTION_MODE;
  24. //
  25. // Instruction size definition (for operand and address)
  26. //
  27. typedef enum {
  28. Size8Bits = 0,
  29. Size16Bits,
  30. Size32Bits,
  31. Size64Bits,
  32. } SEV_ES_INSTRUCTION_SIZE;
  33. //
  34. // Intruction segment definition
  35. //
  36. typedef enum {
  37. SegmentEs = 0,
  38. SegmentCs,
  39. SegmentSs,
  40. SegmentDs,
  41. SegmentFs,
  42. SegmentGs,
  43. } SEV_ES_INSTRUCTION_SEGMENT;
  44. //
  45. // Instruction rep function definition
  46. //
  47. typedef enum {
  48. RepNone = 0,
  49. RepZ,
  50. RepNZ,
  51. } SEV_ES_INSTRUCTION_REP;
  52. typedef struct {
  53. UINT8 Rm;
  54. UINT8 Reg;
  55. UINT8 Mod;
  56. } SEV_ES_INSTRUCTION_MODRM_EXT;
  57. typedef struct {
  58. UINT8 Base;
  59. UINT8 Index;
  60. UINT8 Scale;
  61. } SEV_ES_INSTRUCTION_SIB_EXT;
  62. //
  63. // Instruction opcode definition
  64. //
  65. typedef struct {
  66. SEV_ES_INSTRUCTION_MODRM_EXT ModRm;
  67. SEV_ES_INSTRUCTION_SIB_EXT Sib;
  68. UINTN RegData;
  69. UINTN RmData;
  70. } SEV_ES_INSTRUCTION_OPCODE_EXT;
  71. //
  72. // Instruction parsing context definition
  73. //
  74. typedef struct {
  75. GHCB *Ghcb;
  76. SEV_ES_INSTRUCTION_MODE Mode;
  77. SEV_ES_INSTRUCTION_SIZE DataSize;
  78. SEV_ES_INSTRUCTION_SIZE AddrSize;
  79. BOOLEAN SegmentSpecified;
  80. SEV_ES_INSTRUCTION_SEGMENT Segment;
  81. SEV_ES_INSTRUCTION_REP RepMode;
  82. UINT8 *Begin;
  83. UINT8 *End;
  84. UINT8 *Prefixes;
  85. UINT8 *OpCodes;
  86. UINT8 *Displacement;
  87. UINT8 *Immediate;
  88. INSTRUCTION_REX_PREFIX RexPrefix;
  89. BOOLEAN ModRmPresent;
  90. INSTRUCTION_MODRM ModRm;
  91. BOOLEAN SibPresent;
  92. INSTRUCTION_SIB Sib;
  93. UINTN PrefixSize;
  94. UINTN OpCodeSize;
  95. UINTN DisplacementSize;
  96. UINTN ImmediateSize;
  97. SEV_ES_INSTRUCTION_OPCODE_EXT Ext;
  98. } SEV_ES_INSTRUCTION_DATA;
  99. //
  100. // Non-automatic Exit function prototype
  101. //
  102. typedef
  103. UINT64
  104. (*NAE_EXIT) (
  105. GHCB *Ghcb,
  106. EFI_SYSTEM_CONTEXT_X64 *Regs,
  107. SEV_ES_INSTRUCTION_DATA *InstructionData
  108. );
  109. //
  110. // SEV-SNP Cpuid table entry/function
  111. //
  112. typedef PACKED struct {
  113. UINT32 EaxIn;
  114. UINT32 EcxIn;
  115. UINT64 Unused;
  116. UINT64 Unused2;
  117. UINT32 Eax;
  118. UINT32 Ebx;
  119. UINT32 Ecx;
  120. UINT32 Edx;
  121. UINT64 Reserved;
  122. } SEV_SNP_CPUID_FUNCTION;
  123. //
  124. // SEV-SNP Cpuid page format
  125. //
  126. typedef PACKED struct {
  127. UINT32 Count;
  128. UINT32 Reserved1;
  129. UINT64 Reserved2;
  130. SEV_SNP_CPUID_FUNCTION function[0];
  131. } SEV_SNP_CPUID_INFO;
  132. /**
  133. Return a pointer to the contents of the specified register.
  134. Based upon the input register, return a pointer to the registers contents
  135. in the x86 processor context.
  136. @param[in] Regs x64 processor context
  137. @param[in] Register Register to obtain pointer for
  138. @return Pointer to the contents of the requested register
  139. **/
  140. STATIC
  141. UINT64 *
  142. GetRegisterPointer (
  143. IN EFI_SYSTEM_CONTEXT_X64 *Regs,
  144. IN UINT8 Register
  145. )
  146. {
  147. UINT64 *Reg;
  148. switch (Register) {
  149. case 0:
  150. Reg = &Regs->Rax;
  151. break;
  152. case 1:
  153. Reg = &Regs->Rcx;
  154. break;
  155. case 2:
  156. Reg = &Regs->Rdx;
  157. break;
  158. case 3:
  159. Reg = &Regs->Rbx;
  160. break;
  161. case 4:
  162. Reg = &Regs->Rsp;
  163. break;
  164. case 5:
  165. Reg = &Regs->Rbp;
  166. break;
  167. case 6:
  168. Reg = &Regs->Rsi;
  169. break;
  170. case 7:
  171. Reg = &Regs->Rdi;
  172. break;
  173. case 8:
  174. Reg = &Regs->R8;
  175. break;
  176. case 9:
  177. Reg = &Regs->R9;
  178. break;
  179. case 10:
  180. Reg = &Regs->R10;
  181. break;
  182. case 11:
  183. Reg = &Regs->R11;
  184. break;
  185. case 12:
  186. Reg = &Regs->R12;
  187. break;
  188. case 13:
  189. Reg = &Regs->R13;
  190. break;
  191. case 14:
  192. Reg = &Regs->R14;
  193. break;
  194. case 15:
  195. Reg = &Regs->R15;
  196. break;
  197. default:
  198. Reg = NULL;
  199. }
  200. ASSERT (Reg != NULL);
  201. return Reg;
  202. }
  203. /**
  204. Update the instruction parsing context for displacement bytes.
  205. @param[in, out] InstructionData Instruction parsing context
  206. @param[in] Size The instruction displacement size
  207. **/
  208. STATIC
  209. VOID
  210. UpdateForDisplacement (
  211. IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData,
  212. IN UINTN Size
  213. )
  214. {
  215. InstructionData->DisplacementSize = Size;
  216. InstructionData->Immediate += Size;
  217. InstructionData->End += Size;
  218. }
  219. /**
  220. Determine if an instruction address if RIP relative.
  221. Examine the instruction parsing context to determine if the address offset
  222. is relative to the instruction pointer.
  223. @param[in] InstructionData Instruction parsing context
  224. @retval TRUE Instruction addressing is RIP relative
  225. @retval FALSE Instruction addressing is not RIP relative
  226. **/
  227. STATIC
  228. BOOLEAN
  229. IsRipRelative (
  230. IN SEV_ES_INSTRUCTION_DATA *InstructionData
  231. )
  232. {
  233. SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;
  234. Ext = &InstructionData->Ext;
  235. return ((InstructionData->Mode == LongMode64Bit) &&
  236. (Ext->ModRm.Mod == 0) &&
  237. (Ext->ModRm.Rm == 5) &&
  238. (InstructionData->SibPresent == FALSE));
  239. }
  240. /**
  241. Return the effective address of a memory operand.
  242. Examine the instruction parsing context to obtain the effective memory
  243. address of a memory operand.
  244. @param[in] Regs x64 processor context
  245. @param[in] InstructionData Instruction parsing context
  246. @return The memory operand effective address
  247. **/
  248. STATIC
  249. UINT64
  250. GetEffectiveMemoryAddress (
  251. IN EFI_SYSTEM_CONTEXT_X64 *Regs,
  252. IN SEV_ES_INSTRUCTION_DATA *InstructionData
  253. )
  254. {
  255. SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;
  256. UINT64 EffectiveAddress;
  257. Ext = &InstructionData->Ext;
  258. EffectiveAddress = 0;
  259. if (IsRipRelative (InstructionData)) {
  260. //
  261. // RIP-relative displacement is a 32-bit signed value
  262. //
  263. INT32 RipRelative;
  264. RipRelative = *(INT32 *)InstructionData->Displacement;
  265. UpdateForDisplacement (InstructionData, 4);
  266. //
  267. // Negative displacement is handled by standard UINT64 wrap-around.
  268. //
  269. return Regs->Rip + (UINT64)RipRelative;
  270. }
  271. switch (Ext->ModRm.Mod) {
  272. case 1:
  273. UpdateForDisplacement (InstructionData, 1);
  274. EffectiveAddress += (UINT64)(*(INT8 *)(InstructionData->Displacement));
  275. break;
  276. case 2:
  277. switch (InstructionData->AddrSize) {
  278. case Size16Bits:
  279. UpdateForDisplacement (InstructionData, 2);
  280. EffectiveAddress += (UINT64)(*(INT16 *)(InstructionData->Displacement));
  281. break;
  282. default:
  283. UpdateForDisplacement (InstructionData, 4);
  284. EffectiveAddress += (UINT64)(*(INT32 *)(InstructionData->Displacement));
  285. break;
  286. }
  287. break;
  288. }
  289. if (InstructionData->SibPresent) {
  290. INT64 Displacement;
  291. if (Ext->Sib.Index != 4) {
  292. CopyMem (
  293. &Displacement,
  294. GetRegisterPointer (Regs, Ext->Sib.Index),
  295. sizeof (Displacement)
  296. );
  297. Displacement *= (INT64)(1 << Ext->Sib.Scale);
  298. //
  299. // Negative displacement is handled by standard UINT64 wrap-around.
  300. //
  301. EffectiveAddress += (UINT64)Displacement;
  302. }
  303. if ((Ext->Sib.Base != 5) || Ext->ModRm.Mod) {
  304. EffectiveAddress += *GetRegisterPointer (Regs, Ext->Sib.Base);
  305. } else {
  306. UpdateForDisplacement (InstructionData, 4);
  307. EffectiveAddress += (UINT64)(*(INT32 *)(InstructionData->Displacement));
  308. }
  309. } else {
  310. EffectiveAddress += *GetRegisterPointer (Regs, Ext->ModRm.Rm);
  311. }
  312. return EffectiveAddress;
  313. }
  314. /**
  315. Decode a ModRM byte.
  316. Examine the instruction parsing context to decode a ModRM byte and the SIB
  317. byte, if present.
  318. @param[in] Regs x64 processor context
  319. @param[in, out] InstructionData Instruction parsing context
  320. **/
  321. STATIC
  322. VOID
  323. DecodeModRm (
  324. IN EFI_SYSTEM_CONTEXT_X64 *Regs,
  325. IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData
  326. )
  327. {
  328. SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;
  329. INSTRUCTION_REX_PREFIX *RexPrefix;
  330. INSTRUCTION_MODRM *ModRm;
  331. INSTRUCTION_SIB *Sib;
  332. RexPrefix = &InstructionData->RexPrefix;
  333. Ext = &InstructionData->Ext;
  334. ModRm = &InstructionData->ModRm;
  335. Sib = &InstructionData->Sib;
  336. InstructionData->ModRmPresent = TRUE;
  337. ModRm->Uint8 = *(InstructionData->End);
  338. InstructionData->Displacement++;
  339. InstructionData->Immediate++;
  340. InstructionData->End++;
  341. Ext->ModRm.Mod = ModRm->Bits.Mod;
  342. Ext->ModRm.Reg = (RexPrefix->Bits.BitR << 3) | ModRm->Bits.Reg;
  343. Ext->ModRm.Rm = (RexPrefix->Bits.BitB << 3) | ModRm->Bits.Rm;
  344. Ext->RegData = *GetRegisterPointer (Regs, Ext->ModRm.Reg);
  345. if (Ext->ModRm.Mod == 3) {
  346. Ext->RmData = *GetRegisterPointer (Regs, Ext->ModRm.Rm);
  347. } else {
  348. if (ModRm->Bits.Rm == 4) {
  349. InstructionData->SibPresent = TRUE;
  350. Sib->Uint8 = *(InstructionData->End);
  351. InstructionData->Displacement++;
  352. InstructionData->Immediate++;
  353. InstructionData->End++;
  354. Ext->Sib.Scale = Sib->Bits.Scale;
  355. Ext->Sib.Index = (RexPrefix->Bits.BitX << 3) | Sib->Bits.Index;
  356. Ext->Sib.Base = (RexPrefix->Bits.BitB << 3) | Sib->Bits.Base;
  357. }
  358. Ext->RmData = GetEffectiveMemoryAddress (Regs, InstructionData);
  359. }
  360. }
  361. /**
  362. Decode instruction prefixes.
  363. Parse the instruction data to track the instruction prefixes that have
  364. been used.
  365. @param[in] Regs x64 processor context
  366. @param[in, out] InstructionData Instruction parsing context
  367. **/
  368. STATIC
  369. VOID
  370. DecodePrefixes (
  371. IN EFI_SYSTEM_CONTEXT_X64 *Regs,
  372. IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData
  373. )
  374. {
  375. SEV_ES_INSTRUCTION_MODE Mode;
  376. SEV_ES_INSTRUCTION_SIZE ModeDataSize;
  377. SEV_ES_INSTRUCTION_SIZE ModeAddrSize;
  378. UINT8 *Byte;
  379. //
  380. // Always in 64-bit mode
  381. //
  382. Mode = LongMode64Bit;
  383. ModeDataSize = Size32Bits;
  384. ModeAddrSize = Size64Bits;
  385. InstructionData->Mode = Mode;
  386. InstructionData->DataSize = ModeDataSize;
  387. InstructionData->AddrSize = ModeAddrSize;
  388. InstructionData->Prefixes = InstructionData->Begin;
  389. Byte = InstructionData->Prefixes;
  390. for ( ; ; Byte++, InstructionData->PrefixSize++) {
  391. //
  392. // Check the 0x40 to 0x4F range using an if statement here since some
  393. // compilers don't like the "case 0x40 ... 0x4F:" syntax. This avoids
  394. // 16 case statements below.
  395. //
  396. if ((*Byte >= REX_PREFIX_START) && (*Byte <= REX_PREFIX_STOP)) {
  397. InstructionData->RexPrefix.Uint8 = *Byte;
  398. if ((*Byte & REX_64BIT_OPERAND_SIZE_MASK) != 0) {
  399. InstructionData->DataSize = Size64Bits;
  400. }
  401. continue;
  402. }
  403. switch (*Byte) {
  404. case OVERRIDE_SEGMENT_CS:
  405. case OVERRIDE_SEGMENT_DS:
  406. case OVERRIDE_SEGMENT_ES:
  407. case OVERRIDE_SEGMENT_SS:
  408. if (Mode != LongMode64Bit) {
  409. InstructionData->SegmentSpecified = TRUE;
  410. InstructionData->Segment = (*Byte >> 3) & 3;
  411. }
  412. break;
  413. case OVERRIDE_SEGMENT_FS:
  414. case OVERRIDE_SEGMENT_GS:
  415. InstructionData->SegmentSpecified = TRUE;
  416. InstructionData->Segment = *Byte & 7;
  417. break;
  418. case OVERRIDE_OPERAND_SIZE:
  419. if (InstructionData->RexPrefix.Uint8 == 0) {
  420. InstructionData->DataSize =
  421. (Mode == LongMode64Bit) ? Size16Bits :
  422. (Mode == LongModeCompat32Bit) ? Size16Bits :
  423. (Mode == LongModeCompat16Bit) ? Size32Bits : 0;
  424. }
  425. break;
  426. case OVERRIDE_ADDRESS_SIZE:
  427. InstructionData->AddrSize =
  428. (Mode == LongMode64Bit) ? Size32Bits :
  429. (Mode == LongModeCompat32Bit) ? Size16Bits :
  430. (Mode == LongModeCompat16Bit) ? Size32Bits : 0;
  431. break;
  432. case LOCK_PREFIX:
  433. break;
  434. case REPZ_PREFIX:
  435. InstructionData->RepMode = RepZ;
  436. break;
  437. case REPNZ_PREFIX:
  438. InstructionData->RepMode = RepNZ;
  439. break;
  440. default:
  441. InstructionData->OpCodes = Byte;
  442. InstructionData->OpCodeSize = (*Byte == TWO_BYTE_OPCODE_ESCAPE) ? 2 : 1;
  443. InstructionData->End = Byte + InstructionData->OpCodeSize;
  444. InstructionData->Displacement = InstructionData->End;
  445. InstructionData->Immediate = InstructionData->End;
  446. return;
  447. }
  448. }
  449. }
  450. /**
  451. Determine instruction length
  452. Return the total length of the parsed instruction.
  453. @param[in] InstructionData Instruction parsing context
  454. @return Length of parsed instruction
  455. **/
  456. STATIC
  457. UINT64
  458. InstructionLength (
  459. IN SEV_ES_INSTRUCTION_DATA *InstructionData
  460. )
  461. {
  462. return (UINT64)(InstructionData->End - InstructionData->Begin);
  463. }
  464. /**
  465. Initialize the instruction parsing context.
  466. Initialize the instruction parsing context, which includes decoding the
  467. instruction prefixes.
  468. @param[in, out] InstructionData Instruction parsing context
  469. @param[in] Ghcb Pointer to the Guest-Hypervisor Communication
  470. Block
  471. @param[in] Regs x64 processor context
  472. **/
  473. STATIC
  474. VOID
  475. InitInstructionData (
  476. IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData,
  477. IN GHCB *Ghcb,
  478. IN EFI_SYSTEM_CONTEXT_X64 *Regs
  479. )
  480. {
  481. SetMem (InstructionData, sizeof (*InstructionData), 0);
  482. InstructionData->Ghcb = Ghcb;
  483. InstructionData->Begin = (UINT8 *)Regs->Rip;
  484. InstructionData->End = (UINT8 *)Regs->Rip;
  485. DecodePrefixes (Regs, InstructionData);
  486. }
  487. /**
  488. Report an unsupported event to the hypervisor
  489. Use the VMGEXIT support to report an unsupported event to the hypervisor.
  490. @param[in] Ghcb Pointer to the Guest-Hypervisor Communication
  491. Block
  492. @param[in] Regs x64 processor context
  493. @param[in] InstructionData Instruction parsing context
  494. @return New exception value to propagate
  495. **/
  496. STATIC
  497. UINT64
  498. UnsupportedExit (
  499. IN GHCB *Ghcb,
  500. IN EFI_SYSTEM_CONTEXT_X64 *Regs,
  501. IN SEV_ES_INSTRUCTION_DATA *InstructionData
  502. )
  503. {
  504. UINT64 Status;
  505. Status = VmgExit (Ghcb, SVM_EXIT_UNSUPPORTED, Regs->ExceptionData, 0);
  506. if (Status == 0) {
  507. GHCB_EVENT_INJECTION Event;
  508. Event.Uint64 = 0;
  509. Event.Elements.Vector = GP_EXCEPTION;
  510. Event.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION;
  511. Event.Elements.Valid = 1;
  512. Status = Event.Uint64;
  513. }
  514. return Status;
  515. }
  516. /**
  517. Validate that the MMIO memory access is not to encrypted memory.
  518. Examine the pagetable entry for the memory specified. MMIO should not be
  519. performed against encrypted memory. MMIO to the APIC page is always allowed.
  520. @param[in] Ghcb Pointer to the Guest-Hypervisor Communication Block
  521. @param[in] MemoryAddress Memory address to validate
  522. @param[in] MemoryLength Memory length to validate
  523. @retval 0 Memory is not encrypted
  524. @return New exception value to propogate
  525. **/
  526. STATIC
  527. UINT64
  528. ValidateMmioMemory (
  529. IN GHCB *Ghcb,
  530. IN UINTN MemoryAddress,
  531. IN UINTN MemoryLength
  532. )
  533. {
  534. MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE State;
  535. GHCB_EVENT_INJECTION GpEvent;
  536. UINTN Address;
  537. //
  538. // Allow APIC accesses (which will have the encryption bit set during
  539. // SEC and PEI phases).
  540. //
  541. Address = MemoryAddress & ~(SIZE_4KB - 1);
  542. if (Address == GetLocalApicBaseAddress ()) {
  543. return 0;
  544. }
  545. State = MemEncryptSevGetAddressRangeState (
  546. 0,
  547. MemoryAddress,
  548. MemoryLength
  549. );
  550. if (State == MemEncryptSevAddressRangeUnencrypted) {
  551. return 0;
  552. }
  553. //
  554. // Any state other than unencrypted is an error, issue a #GP.
  555. //
  556. DEBUG ((
  557. DEBUG_ERROR,
  558. "MMIO using encrypted memory: %lx\n",
  559. (UINT64)MemoryAddress
  560. ));
  561. GpEvent.Uint64 = 0;
  562. GpEvent.Elements.Vector = GP_EXCEPTION;
  563. GpEvent.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION;
  564. GpEvent.Elements.Valid = 1;
  565. return GpEvent.Uint64;
  566. }
  567. /**
  568. Handle an MMIO event.
  569. Use the VMGEXIT instruction to handle either an MMIO read or an MMIO write.
  570. @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
  571. Block
  572. @param[in, out] Regs x64 processor context
  573. @param[in, out] InstructionData Instruction parsing context
  574. @retval 0 Event handled successfully
  575. @return New exception value to propagate
  576. **/
  577. STATIC
  578. UINT64
  579. MmioExit (
  580. IN OUT GHCB *Ghcb,
  581. IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
  582. IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData
  583. )
  584. {
  585. UINT64 ExitInfo1, ExitInfo2, Status;
  586. UINTN Bytes;
  587. UINT64 *Register;
  588. UINT8 OpCode, SignByte;
  589. UINTN Address;
  590. Bytes = 0;
  591. OpCode = *(InstructionData->OpCodes);
  592. if (OpCode == TWO_BYTE_OPCODE_ESCAPE) {
  593. OpCode = *(InstructionData->OpCodes + 1);
  594. }
  595. switch (OpCode) {
  596. //
  597. // MMIO write (MOV reg/memX, regX)
  598. //
  599. case 0x88:
  600. Bytes = 1;
  601. //
  602. // fall through
  603. //
  604. case 0x89:
  605. DecodeModRm (Regs, InstructionData);
  606. Bytes = ((Bytes != 0) ? Bytes :
  607. (InstructionData->DataSize == Size16Bits) ? 2 :
  608. (InstructionData->DataSize == Size32Bits) ? 4 :
  609. (InstructionData->DataSize == Size64Bits) ? 8 :
  610. 0);
  611. if (InstructionData->Ext.ModRm.Mod == 3) {
  612. //
  613. // NPF on two register operands???
  614. //
  615. return UnsupportedExit (Ghcb, Regs, InstructionData);
  616. }
  617. Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);
  618. if (Status != 0) {
  619. return Status;
  620. }
  621. ExitInfo1 = InstructionData->Ext.RmData;
  622. ExitInfo2 = Bytes;
  623. CopyMem (Ghcb->SharedBuffer, &InstructionData->Ext.RegData, Bytes);
  624. Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
  625. VmgSetOffsetValid (Ghcb, GhcbSwScratch);
  626. Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);
  627. if (Status != 0) {
  628. return Status;
  629. }
  630. break;
  631. //
  632. // MMIO write (MOV moffsetX, aX)
  633. //
  634. case 0xA2:
  635. Bytes = 1;
  636. //
  637. // fall through
  638. //
  639. case 0xA3:
  640. Bytes = ((Bytes != 0) ? Bytes :
  641. (InstructionData->DataSize == Size16Bits) ? 2 :
  642. (InstructionData->DataSize == Size32Bits) ? 4 :
  643. (InstructionData->DataSize == Size64Bits) ? 8 :
  644. 0);
  645. InstructionData->ImmediateSize = (UINTN)(1 << InstructionData->AddrSize);
  646. InstructionData->End += InstructionData->ImmediateSize;
  647. //
  648. // This code is X64 only, so a possible 8-byte copy to a UINTN is ok.
  649. // Use a STATIC_ASSERT to be certain the code is being built as X64.
  650. //
  651. STATIC_ASSERT (
  652. sizeof (UINTN) == sizeof (UINT64),
  653. "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64"
  654. );
  655. Address = 0;
  656. CopyMem (
  657. &Address,
  658. InstructionData->Immediate,
  659. InstructionData->ImmediateSize
  660. );
  661. Status = ValidateMmioMemory (Ghcb, Address, Bytes);
  662. if (Status != 0) {
  663. return Status;
  664. }
  665. ExitInfo1 = Address;
  666. ExitInfo2 = Bytes;
  667. CopyMem (Ghcb->SharedBuffer, &Regs->Rax, Bytes);
  668. Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
  669. VmgSetOffsetValid (Ghcb, GhcbSwScratch);
  670. Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);
  671. if (Status != 0) {
  672. return Status;
  673. }
  674. break;
  675. //
  676. // MMIO write (MOV reg/memX, immX)
  677. //
  678. case 0xC6:
  679. Bytes = 1;
  680. //
  681. // fall through
  682. //
  683. case 0xC7:
  684. DecodeModRm (Regs, InstructionData);
  685. Bytes = ((Bytes != 0) ? Bytes :
  686. (InstructionData->DataSize == Size16Bits) ? 2 :
  687. (InstructionData->DataSize == Size32Bits) ? 4 :
  688. 0);
  689. InstructionData->ImmediateSize = Bytes;
  690. InstructionData->End += Bytes;
  691. Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);
  692. if (Status != 0) {
  693. return Status;
  694. }
  695. ExitInfo1 = InstructionData->Ext.RmData;
  696. ExitInfo2 = Bytes;
  697. CopyMem (Ghcb->SharedBuffer, InstructionData->Immediate, Bytes);
  698. Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
  699. VmgSetOffsetValid (Ghcb, GhcbSwScratch);
  700. Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);
  701. if (Status != 0) {
  702. return Status;
  703. }
  704. break;
  705. //
  706. // MMIO read (MOV regX, reg/memX)
  707. //
  708. case 0x8A:
  709. Bytes = 1;
  710. //
  711. // fall through
  712. //
  713. case 0x8B:
  714. DecodeModRm (Regs, InstructionData);
  715. Bytes = ((Bytes != 0) ? Bytes :
  716. (InstructionData->DataSize == Size16Bits) ? 2 :
  717. (InstructionData->DataSize == Size32Bits) ? 4 :
  718. (InstructionData->DataSize == Size64Bits) ? 8 :
  719. 0);
  720. if (InstructionData->Ext.ModRm.Mod == 3) {
  721. //
  722. // NPF on two register operands???
  723. //
  724. return UnsupportedExit (Ghcb, Regs, InstructionData);
  725. }
  726. Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);
  727. if (Status != 0) {
  728. return Status;
  729. }
  730. ExitInfo1 = InstructionData->Ext.RmData;
  731. ExitInfo2 = Bytes;
  732. Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
  733. VmgSetOffsetValid (Ghcb, GhcbSwScratch);
  734. Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);
  735. if (Status != 0) {
  736. return Status;
  737. }
  738. Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);
  739. if (Bytes == 4) {
  740. //
  741. // Zero-extend for 32-bit operation
  742. //
  743. *Register = 0;
  744. }
  745. CopyMem (Register, Ghcb->SharedBuffer, Bytes);
  746. break;
  747. //
  748. // MMIO read (MOV aX, moffsetX)
  749. //
  750. case 0xA0:
  751. Bytes = 1;
  752. //
  753. // fall through
  754. //
  755. case 0xA1:
  756. Bytes = ((Bytes != 0) ? Bytes :
  757. (InstructionData->DataSize == Size16Bits) ? 2 :
  758. (InstructionData->DataSize == Size32Bits) ? 4 :
  759. (InstructionData->DataSize == Size64Bits) ? 8 :
  760. 0);
  761. InstructionData->ImmediateSize = (UINTN)(1 << InstructionData->AddrSize);
  762. InstructionData->End += InstructionData->ImmediateSize;
  763. //
  764. // This code is X64 only, so a possible 8-byte copy to a UINTN is ok.
  765. // Use a STATIC_ASSERT to be certain the code is being built as X64.
  766. //
  767. STATIC_ASSERT (
  768. sizeof (UINTN) == sizeof (UINT64),
  769. "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64"
  770. );
  771. Address = 0;
  772. CopyMem (
  773. &Address,
  774. InstructionData->Immediate,
  775. InstructionData->ImmediateSize
  776. );
  777. Status = ValidateMmioMemory (Ghcb, Address, Bytes);
  778. if (Status != 0) {
  779. return Status;
  780. }
  781. ExitInfo1 = Address;
  782. ExitInfo2 = Bytes;
  783. Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
  784. VmgSetOffsetValid (Ghcb, GhcbSwScratch);
  785. Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);
  786. if (Status != 0) {
  787. return Status;
  788. }
  789. if (Bytes == 4) {
  790. //
  791. // Zero-extend for 32-bit operation
  792. //
  793. Regs->Rax = 0;
  794. }
  795. CopyMem (&Regs->Rax, Ghcb->SharedBuffer, Bytes);
  796. break;
  797. //
  798. // MMIO read w/ zero-extension ((MOVZX regX, reg/memX)
  799. //
  800. case 0xB6:
  801. Bytes = 1;
  802. //
  803. // fall through
  804. //
  805. case 0xB7:
  806. DecodeModRm (Regs, InstructionData);
  807. Bytes = (Bytes != 0) ? Bytes : 2;
  808. Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);
  809. if (Status != 0) {
  810. return Status;
  811. }
  812. ExitInfo1 = InstructionData->Ext.RmData;
  813. ExitInfo2 = Bytes;
  814. Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
  815. VmgSetOffsetValid (Ghcb, GhcbSwScratch);
  816. Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);
  817. if (Status != 0) {
  818. return Status;
  819. }
  820. Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);
  821. SetMem (Register, (UINTN)(1 << InstructionData->DataSize), 0);
  822. CopyMem (Register, Ghcb->SharedBuffer, Bytes);
  823. break;
  824. //
  825. // MMIO read w/ sign-extension (MOVSX regX, reg/memX)
  826. //
  827. case 0xBE:
  828. Bytes = 1;
  829. //
  830. // fall through
  831. //
  832. case 0xBF:
  833. DecodeModRm (Regs, InstructionData);
  834. Bytes = (Bytes != 0) ? Bytes : 2;
  835. Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);
  836. if (Status != 0) {
  837. return Status;
  838. }
  839. ExitInfo1 = InstructionData->Ext.RmData;
  840. ExitInfo2 = Bytes;
  841. Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
  842. VmgSetOffsetValid (Ghcb, GhcbSwScratch);
  843. Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);
  844. if (Status != 0) {
  845. return Status;
  846. }
  847. if (Bytes == 1) {
  848. UINT8 *Data;
  849. Data = (UINT8 *)Ghcb->SharedBuffer;
  850. SignByte = ((*Data & BIT7) != 0) ? 0xFF : 0x00;
  851. } else {
  852. UINT16 *Data;
  853. Data = (UINT16 *)Ghcb->SharedBuffer;
  854. SignByte = ((*Data & BIT15) != 0) ? 0xFF : 0x00;
  855. }
  856. Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);
  857. SetMem (Register, (UINTN)(1 << InstructionData->DataSize), SignByte);
  858. CopyMem (Register, Ghcb->SharedBuffer, Bytes);
  859. break;
  860. default:
  861. DEBUG ((DEBUG_ERROR, "Invalid MMIO opcode (%x)\n", OpCode));
  862. Status = GP_EXCEPTION;
  863. ASSERT (FALSE);
  864. }
  865. return Status;
  866. }
  867. /**
  868. Handle a MWAIT event.
  869. Use the VMGEXIT instruction to handle a MWAIT event.
  870. @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
  871. Block
  872. @param[in, out] Regs x64 processor context
  873. @param[in] InstructionData Instruction parsing context
  874. @retval 0 Event handled successfully
  875. @return New exception value to propagate
  876. **/
  877. STATIC
  878. UINT64
  879. MwaitExit (
  880. IN OUT GHCB *Ghcb,
  881. IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
  882. IN SEV_ES_INSTRUCTION_DATA *InstructionData
  883. )
  884. {
  885. DecodeModRm (Regs, InstructionData);
  886. Ghcb->SaveArea.Rax = Regs->Rax;
  887. VmgSetOffsetValid (Ghcb, GhcbRax);
  888. Ghcb->SaveArea.Rcx = Regs->Rcx;
  889. VmgSetOffsetValid (Ghcb, GhcbRcx);
  890. return VmgExit (Ghcb, SVM_EXIT_MWAIT, 0, 0);
  891. }
  892. /**
  893. Handle a MONITOR event.
  894. Use the VMGEXIT instruction to handle a MONITOR event.
  895. @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
  896. Block
  897. @param[in, out] Regs x64 processor context
  898. @param[in] InstructionData Instruction parsing context
  899. @retval 0 Event handled successfully
  900. @return New exception value to propagate
  901. **/
  902. STATIC
  903. UINT64
  904. MonitorExit (
  905. IN OUT GHCB *Ghcb,
  906. IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
  907. IN SEV_ES_INSTRUCTION_DATA *InstructionData
  908. )
  909. {
  910. DecodeModRm (Regs, InstructionData);
  911. Ghcb->SaveArea.Rax = Regs->Rax; // Identity mapped, so VA = PA
  912. VmgSetOffsetValid (Ghcb, GhcbRax);
  913. Ghcb->SaveArea.Rcx = Regs->Rcx;
  914. VmgSetOffsetValid (Ghcb, GhcbRcx);
  915. Ghcb->SaveArea.Rdx = Regs->Rdx;
  916. VmgSetOffsetValid (Ghcb, GhcbRdx);
  917. return VmgExit (Ghcb, SVM_EXIT_MONITOR, 0, 0);
  918. }
  919. /**
  920. Handle a WBINVD event.
  921. Use the VMGEXIT instruction to handle a WBINVD event.
  922. @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
  923. Block
  924. @param[in, out] Regs x64 processor context
  925. @param[in] InstructionData Instruction parsing context
  926. @retval 0 Event handled successfully
  927. @return New exception value to propagate
  928. **/
  929. STATIC
  930. UINT64
  931. WbinvdExit (
  932. IN OUT GHCB *Ghcb,
  933. IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
  934. IN SEV_ES_INSTRUCTION_DATA *InstructionData
  935. )
  936. {
  937. return VmgExit (Ghcb, SVM_EXIT_WBINVD, 0, 0);
  938. }
  939. /**
  940. Handle a RDTSCP event.
  941. Use the VMGEXIT instruction to handle a RDTSCP event.
  942. @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
  943. Block
  944. @param[in, out] Regs x64 processor context
  945. @param[in] InstructionData Instruction parsing context
  946. @retval 0 Event handled successfully
  947. @return New exception value to propagate
  948. **/
  949. STATIC
  950. UINT64
  951. RdtscpExit (
  952. IN OUT GHCB *Ghcb,
  953. IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
  954. IN SEV_ES_INSTRUCTION_DATA *InstructionData
  955. )
  956. {
  957. UINT64 Status;
  958. DecodeModRm (Regs, InstructionData);
  959. Status = VmgExit (Ghcb, SVM_EXIT_RDTSCP, 0, 0);
  960. if (Status != 0) {
  961. return Status;
  962. }
  963. if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||
  964. !VmgIsOffsetValid (Ghcb, GhcbRcx) ||
  965. !VmgIsOffsetValid (Ghcb, GhcbRdx))
  966. {
  967. return UnsupportedExit (Ghcb, Regs, InstructionData);
  968. }
  969. Regs->Rax = Ghcb->SaveArea.Rax;
  970. Regs->Rcx = Ghcb->SaveArea.Rcx;
  971. Regs->Rdx = Ghcb->SaveArea.Rdx;
  972. return 0;
  973. }
  974. /**
  975. Handle a VMMCALL event.
  976. Use the VMGEXIT instruction to handle a VMMCALL event.
  977. @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
  978. Block
  979. @param[in, out] Regs x64 processor context
  980. @param[in] InstructionData Instruction parsing context
  981. @retval 0 Event handled successfully
  982. @return New exception value to propagate
  983. **/
  984. STATIC
  985. UINT64
  986. VmmCallExit (
  987. IN OUT GHCB *Ghcb,
  988. IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
  989. IN SEV_ES_INSTRUCTION_DATA *InstructionData
  990. )
  991. {
  992. UINT64 Status;
  993. DecodeModRm (Regs, InstructionData);
  994. Ghcb->SaveArea.Rax = Regs->Rax;
  995. VmgSetOffsetValid (Ghcb, GhcbRax);
  996. Ghcb->SaveArea.Cpl = (UINT8)(Regs->Cs & 0x3);
  997. VmgSetOffsetValid (Ghcb, GhcbCpl);
  998. Status = VmgExit (Ghcb, SVM_EXIT_VMMCALL, 0, 0);
  999. if (Status != 0) {
  1000. return Status;
  1001. }
  1002. if (!VmgIsOffsetValid (Ghcb, GhcbRax)) {
  1003. return UnsupportedExit (Ghcb, Regs, InstructionData);
  1004. }
  1005. Regs->Rax = Ghcb->SaveArea.Rax;
  1006. return 0;
  1007. }
  1008. /**
  1009. Handle an MSR event.
  1010. Use the VMGEXIT instruction to handle either a RDMSR or WRMSR event.
  1011. @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
  1012. Block
  1013. @param[in, out] Regs x64 processor context
  1014. @param[in] InstructionData Instruction parsing context
  1015. @retval 0 Event handled successfully
  1016. @return New exception value to propagate
  1017. **/
  1018. STATIC
  1019. UINT64
  1020. MsrExit (
  1021. IN OUT GHCB *Ghcb,
  1022. IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
  1023. IN SEV_ES_INSTRUCTION_DATA *InstructionData
  1024. )
  1025. {
  1026. UINT64 ExitInfo1, Status;
  1027. ExitInfo1 = 0;
  1028. switch (*(InstructionData->OpCodes + 1)) {
  1029. case 0x30: // WRMSR
  1030. ExitInfo1 = 1;
  1031. Ghcb->SaveArea.Rax = Regs->Rax;
  1032. VmgSetOffsetValid (Ghcb, GhcbRax);
  1033. Ghcb->SaveArea.Rdx = Regs->Rdx;
  1034. VmgSetOffsetValid (Ghcb, GhcbRdx);
  1035. //
  1036. // fall through
  1037. //
  1038. case 0x32: // RDMSR
  1039. Ghcb->SaveArea.Rcx = Regs->Rcx;
  1040. VmgSetOffsetValid (Ghcb, GhcbRcx);
  1041. break;
  1042. default:
  1043. return UnsupportedExit (Ghcb, Regs, InstructionData);
  1044. }
  1045. Status = VmgExit (Ghcb, SVM_EXIT_MSR, ExitInfo1, 0);
  1046. if (Status != 0) {
  1047. return Status;
  1048. }
  1049. if (ExitInfo1 == 0) {
  1050. if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||
  1051. !VmgIsOffsetValid (Ghcb, GhcbRdx))
  1052. {
  1053. return UnsupportedExit (Ghcb, Regs, InstructionData);
  1054. }
  1055. Regs->Rax = Ghcb->SaveArea.Rax;
  1056. Regs->Rdx = Ghcb->SaveArea.Rdx;
  1057. }
  1058. return 0;
  1059. }
  1060. /**
  1061. Build the IOIO event information.
  1062. The IOIO event information identifies the type of IO operation to be performed
  1063. by the hypervisor. Build this information based on the instruction data.
  1064. @param[in] Regs x64 processor context
  1065. @param[in, out] InstructionData Instruction parsing context
  1066. @return IOIO event information value
  1067. **/
  1068. STATIC
  1069. UINT64
  1070. IoioExitInfo (
  1071. IN EFI_SYSTEM_CONTEXT_X64 *Regs,
  1072. IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData
  1073. )
  1074. {
  1075. UINT64 ExitInfo;
  1076. ExitInfo = 0;
  1077. switch (*(InstructionData->OpCodes)) {
  1078. //
  1079. // INS opcodes
  1080. //
  1081. case 0x6C:
  1082. case 0x6D:
  1083. ExitInfo |= IOIO_TYPE_INS;
  1084. ExitInfo |= IOIO_SEG_ES;
  1085. ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
  1086. break;
  1087. //
  1088. // OUTS opcodes
  1089. //
  1090. case 0x6E:
  1091. case 0x6F:
  1092. ExitInfo |= IOIO_TYPE_OUTS;
  1093. ExitInfo |= IOIO_SEG_DS;
  1094. ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
  1095. break;
  1096. //
  1097. // IN immediate opcodes
  1098. //
  1099. case 0xE4:
  1100. case 0xE5:
  1101. InstructionData->ImmediateSize = 1;
  1102. InstructionData->End++;
  1103. ExitInfo |= IOIO_TYPE_IN;
  1104. ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16);
  1105. break;
  1106. //
  1107. // OUT immediate opcodes
  1108. //
  1109. case 0xE6:
  1110. case 0xE7:
  1111. InstructionData->ImmediateSize = 1;
  1112. InstructionData->End++;
  1113. ExitInfo |= IOIO_TYPE_OUT;
  1114. ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16) | IOIO_TYPE_OUT;
  1115. break;
  1116. //
  1117. // IN register opcodes
  1118. //
  1119. case 0xEC:
  1120. case 0xED:
  1121. ExitInfo |= IOIO_TYPE_IN;
  1122. ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
  1123. break;
  1124. //
  1125. // OUT register opcodes
  1126. //
  1127. case 0xEE:
  1128. case 0xEF:
  1129. ExitInfo |= IOIO_TYPE_OUT;
  1130. ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
  1131. break;
  1132. default:
  1133. return 0;
  1134. }
  1135. switch (*(InstructionData->OpCodes)) {
  1136. //
  1137. // Single-byte opcodes
  1138. //
  1139. case 0x6C:
  1140. case 0x6E:
  1141. case 0xE4:
  1142. case 0xE6:
  1143. case 0xEC:
  1144. case 0xEE:
  1145. ExitInfo |= IOIO_DATA_8;
  1146. break;
  1147. //
  1148. // Length determined by instruction parsing
  1149. //
  1150. default:
  1151. ExitInfo |= (InstructionData->DataSize == Size16Bits) ? IOIO_DATA_16
  1152. : IOIO_DATA_32;
  1153. }
  1154. switch (InstructionData->AddrSize) {
  1155. case Size16Bits:
  1156. ExitInfo |= IOIO_ADDR_16;
  1157. break;
  1158. case Size32Bits:
  1159. ExitInfo |= IOIO_ADDR_32;
  1160. break;
  1161. case Size64Bits:
  1162. ExitInfo |= IOIO_ADDR_64;
  1163. break;
  1164. default:
  1165. break;
  1166. }
  1167. if (InstructionData->RepMode != 0) {
  1168. ExitInfo |= IOIO_REP;
  1169. }
  1170. return ExitInfo;
  1171. }
  1172. /**
  1173. Handle an IOIO event.
  1174. Use the VMGEXIT instruction to handle an IOIO event.
  1175. @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
  1176. Block
  1177. @param[in, out] Regs x64 processor context
  1178. @param[in] InstructionData Instruction parsing context
  1179. @retval 0 Event handled successfully
  1180. @return New exception value to propagate
  1181. **/
  1182. STATIC
  1183. UINT64
  1184. IoioExit (
  1185. IN OUT GHCB *Ghcb,
  1186. IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
  1187. IN SEV_ES_INSTRUCTION_DATA *InstructionData
  1188. )
  1189. {
  1190. UINT64 ExitInfo1, ExitInfo2, Status;
  1191. BOOLEAN IsString;
  1192. ExitInfo1 = IoioExitInfo (Regs, InstructionData);
  1193. if (ExitInfo1 == 0) {
  1194. return UnsupportedExit (Ghcb, Regs, InstructionData);
  1195. }
  1196. IsString = ((ExitInfo1 & IOIO_TYPE_STR) != 0) ? TRUE : FALSE;
  1197. if (IsString) {
  1198. UINTN IoBytes, VmgExitBytes;
  1199. UINTN GhcbCount, OpCount;
  1200. Status = 0;
  1201. IoBytes = IOIO_DATA_BYTES (ExitInfo1);
  1202. GhcbCount = sizeof (Ghcb->SharedBuffer) / IoBytes;
  1203. OpCount = ((ExitInfo1 & IOIO_REP) != 0) ? Regs->Rcx : 1;
  1204. while (OpCount != 0) {
  1205. ExitInfo2 = MIN (OpCount, GhcbCount);
  1206. VmgExitBytes = ExitInfo2 * IoBytes;
  1207. if ((ExitInfo1 & IOIO_TYPE_IN) == 0) {
  1208. CopyMem (Ghcb->SharedBuffer, (VOID *)Regs->Rsi, VmgExitBytes);
  1209. Regs->Rsi += VmgExitBytes;
  1210. }
  1211. Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
  1212. VmgSetOffsetValid (Ghcb, GhcbSwScratch);
  1213. Status = VmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, ExitInfo2);
  1214. if (Status != 0) {
  1215. return Status;
  1216. }
  1217. if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {
  1218. CopyMem ((VOID *)Regs->Rdi, Ghcb->SharedBuffer, VmgExitBytes);
  1219. Regs->Rdi += VmgExitBytes;
  1220. }
  1221. if ((ExitInfo1 & IOIO_REP) != 0) {
  1222. Regs->Rcx -= ExitInfo2;
  1223. }
  1224. OpCount -= ExitInfo2;
  1225. }
  1226. } else {
  1227. if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {
  1228. Ghcb->SaveArea.Rax = 0;
  1229. } else {
  1230. CopyMem (&Ghcb->SaveArea.Rax, &Regs->Rax, IOIO_DATA_BYTES (ExitInfo1));
  1231. }
  1232. VmgSetOffsetValid (Ghcb, GhcbRax);
  1233. Status = VmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, 0);
  1234. if (Status != 0) {
  1235. return Status;
  1236. }
  1237. if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {
  1238. if (!VmgIsOffsetValid (Ghcb, GhcbRax)) {
  1239. return UnsupportedExit (Ghcb, Regs, InstructionData);
  1240. }
  1241. CopyMem (&Regs->Rax, &Ghcb->SaveArea.Rax, IOIO_DATA_BYTES (ExitInfo1));
  1242. }
  1243. }
  1244. return 0;
  1245. }
  1246. /**
  1247. Handle a INVD event.
  1248. Use the VMGEXIT instruction to handle a INVD event.
  1249. @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
  1250. Block
  1251. @param[in, out] Regs x64 processor context
  1252. @param[in] InstructionData Instruction parsing context
  1253. @retval 0 Event handled successfully
  1254. @return New exception value to propagate
  1255. **/
  1256. STATIC
  1257. UINT64
  1258. InvdExit (
  1259. IN OUT GHCB *Ghcb,
  1260. IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
  1261. IN SEV_ES_INSTRUCTION_DATA *InstructionData
  1262. )
  1263. {
  1264. return VmgExit (Ghcb, SVM_EXIT_INVD, 0, 0);
  1265. }
  1266. /**
  1267. Fetch CPUID leaf/function via hypervisor/VMGEXIT.
  1268. @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
  1269. Block
  1270. @param[in] EaxIn EAX input for cpuid instruction
  1271. @param[in] EcxIn ECX input for cpuid instruction
  1272. @param[in] Xcr0In XCR0 at time of cpuid instruction
  1273. @param[in, out] Eax Pointer to store leaf's EAX value
  1274. @param[in, out] Ebx Pointer to store leaf's EBX value
  1275. @param[in, out] Ecx Pointer to store leaf's ECX value
  1276. @param[in, out] Edx Pointer to store leaf's EDX value
  1277. @param[in, out] Status Pointer to store status from VMGEXIT (always 0
  1278. unless return value indicates failure)
  1279. @param[in, out] Unsupported Pointer to store indication of unsupported
  1280. VMGEXIT (always false unless return value
  1281. indicates failure)
  1282. @retval TRUE CPUID leaf fetch successfully.
  1283. @retval FALSE Error occurred while fetching CPUID leaf. Callers
  1284. should Status and Unsupported and handle
  1285. accordingly if they indicate a more precise
  1286. error condition.
  1287. **/
  1288. STATIC
  1289. BOOLEAN
  1290. GetCpuidHyp (
  1291. IN OUT GHCB *Ghcb,
  1292. IN UINT32 EaxIn,
  1293. IN UINT32 EcxIn,
  1294. IN UINT64 XCr0,
  1295. IN OUT UINT32 *Eax,
  1296. IN OUT UINT32 *Ebx,
  1297. IN OUT UINT32 *Ecx,
  1298. IN OUT UINT32 *Edx,
  1299. IN OUT UINT64 *Status,
  1300. IN OUT BOOLEAN *UnsupportedExit
  1301. )
  1302. {
  1303. *UnsupportedExit = FALSE;
  1304. Ghcb->SaveArea.Rax = EaxIn;
  1305. VmgSetOffsetValid (Ghcb, GhcbRax);
  1306. Ghcb->SaveArea.Rcx = EcxIn;
  1307. VmgSetOffsetValid (Ghcb, GhcbRcx);
  1308. if (EaxIn == CPUID_EXTENDED_STATE) {
  1309. Ghcb->SaveArea.XCr0 = XCr0;
  1310. VmgSetOffsetValid (Ghcb, GhcbXCr0);
  1311. }
  1312. *Status = VmgExit (Ghcb, SVM_EXIT_CPUID, 0, 0);
  1313. if (*Status != 0) {
  1314. return FALSE;
  1315. }
  1316. if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||
  1317. !VmgIsOffsetValid (Ghcb, GhcbRbx) ||
  1318. !VmgIsOffsetValid (Ghcb, GhcbRcx) ||
  1319. !VmgIsOffsetValid (Ghcb, GhcbRdx))
  1320. {
  1321. *UnsupportedExit = TRUE;
  1322. return FALSE;
  1323. }
  1324. if (Eax) {
  1325. *Eax = (UINT32)(UINTN)Ghcb->SaveArea.Rax;
  1326. }
  1327. if (Ebx) {
  1328. *Ebx = (UINT32)(UINTN)Ghcb->SaveArea.Rbx;
  1329. }
  1330. if (Ecx) {
  1331. *Ecx = (UINT32)(UINTN)Ghcb->SaveArea.Rcx;
  1332. }
  1333. if (Edx) {
  1334. *Edx = (UINT32)(UINTN)Ghcb->SaveArea.Rdx;
  1335. }
  1336. return TRUE;
  1337. }
  1338. /**
  1339. Check if SEV-SNP enabled.
  1340. @retval TRUE SEV-SNP is enabled.
  1341. @retval FALSE SEV-SNP is disabled.
  1342. **/
  1343. STATIC
  1344. BOOLEAN
  1345. SnpEnabled (
  1346. VOID
  1347. )
  1348. {
  1349. MSR_SEV_STATUS_REGISTER Msr;
  1350. Msr.Uint32 = AsmReadMsr32 (MSR_SEV_STATUS);
  1351. return !!Msr.Bits.SevSnpBit;
  1352. }
  1353. /**
  1354. Calculate the total XSAVE area size for enabled XSAVE areas
  1355. @param[in] XFeaturesEnabled Bit-mask of enabled XSAVE features/areas as
  1356. indicated by XCR0/MSR_IA32_XSS bits
  1357. @param[in] XSaveBaseSize Base/legacy XSAVE area size (e.g. when
  1358. XCR0 is 1)
  1359. @param[in, out] XSaveSize Pointer to storage for calculated XSAVE area
  1360. size
  1361. @param[in] Compacted Whether or not the calculation is for the
  1362. normal XSAVE area size (leaf 0xD,0x0,EBX) or
  1363. compacted XSAVE area size (leaf 0xD,0x1,EBX)
  1364. @retval TRUE XSAVE size calculation was successful.
  1365. @retval FALSE XSAVE size calculation was unsuccessful.
  1366. **/
  1367. STATIC
  1368. BOOLEAN
  1369. GetCpuidXSaveSize (
  1370. IN UINT64 XFeaturesEnabled,
  1371. IN UINT32 XSaveBaseSize,
  1372. IN OUT UINT32 *XSaveSize,
  1373. IN BOOLEAN Compacted
  1374. )
  1375. {
  1376. SEV_SNP_CPUID_INFO *CpuidInfo;
  1377. UINT64 XFeaturesFound = 0;
  1378. UINT32 Idx;
  1379. *XSaveSize = XSaveBaseSize;
  1380. CpuidInfo = (SEV_SNP_CPUID_INFO *)(UINT64)PcdGet32 (PcdOvmfCpuidBase);
  1381. for (Idx = 0; Idx < CpuidInfo->Count; Idx++) {
  1382. SEV_SNP_CPUID_FUNCTION *CpuidFn = &CpuidInfo->function[Idx];
  1383. if (!((CpuidFn->EaxIn == 0xD) &&
  1384. ((CpuidFn->EcxIn == 0) || (CpuidFn->EcxIn == 1))))
  1385. {
  1386. continue;
  1387. }
  1388. if (XFeaturesFound & (1ULL << CpuidFn->EcxIn) ||
  1389. !(XFeaturesEnabled & (1ULL << CpuidFn->EcxIn)))
  1390. {
  1391. continue;
  1392. }
  1393. XFeaturesFound |= (1ULL << CpuidFn->EcxIn);
  1394. if (Compacted) {
  1395. *XSaveSize += CpuidFn->Eax;
  1396. } else {
  1397. *XSaveSize = MAX (*XSaveSize, CpuidFn->Eax + CpuidFn->Ebx);
  1398. }
  1399. }
  1400. /*
  1401. * Either the guest set unsupported XCR0/XSS bits, or the corresponding
  1402. * entries in the CPUID table were not present. This is an invalid state.
  1403. */
  1404. if (XFeaturesFound != (XFeaturesEnabled & ~3UL)) {
  1405. return FALSE;
  1406. }
  1407. return TRUE;
  1408. }
  1409. /**
  1410. Check if a CPUID leaf/function is indexed via ECX sub-leaf/sub-function
  1411. @param[in] EaxIn EAX input for cpuid instruction
  1412. @retval FALSE cpuid leaf/function is not indexed by ECX input
  1413. @retval TRUE cpuid leaf/function is indexed by ECX input
  1414. **/
  1415. STATIC
  1416. BOOLEAN
  1417. IsFunctionIndexed (
  1418. IN UINT32 EaxIn
  1419. )
  1420. {
  1421. switch (EaxIn) {
  1422. case CPUID_CACHE_PARAMS:
  1423. case CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS:
  1424. case CPUID_EXTENDED_TOPOLOGY:
  1425. case CPUID_EXTENDED_STATE:
  1426. case CPUID_INTEL_RDT_MONITORING:
  1427. case CPUID_INTEL_RDT_ALLOCATION:
  1428. case CPUID_INTEL_SGX:
  1429. case CPUID_INTEL_PROCESSOR_TRACE:
  1430. case CPUID_DETERMINISTIC_ADDRESS_TRANSLATION_PARAMETERS:
  1431. case CPUID_V2_EXTENDED_TOPOLOGY:
  1432. case 0x8000001D: /* Cache Topology Information */
  1433. return TRUE;
  1434. }
  1435. return FALSE;
  1436. }
  1437. /**
  1438. Fetch CPUID leaf/function via SEV-SNP CPUID table.
  1439. @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
  1440. Block
  1441. @param[in] EaxIn EAX input for cpuid instruction
  1442. @param[in] EcxIn ECX input for cpuid instruction
  1443. @param[in] Xcr0In XCR0 at time of cpuid instruction
  1444. @param[in, out] Eax Pointer to store leaf's EAX value
  1445. @param[in, out] Ebx Pointer to store leaf's EBX value
  1446. @param[in, out] Ecx Pointer to store leaf's ECX value
  1447. @param[in, out] Edx Pointer to store leaf's EDX value
  1448. @param[in, out] Status Pointer to store status from VMGEXIT (always 0
  1449. unless return value indicates failure)
  1450. @param[in, out] Unsupported Pointer to store indication of unsupported
  1451. VMGEXIT (always false unless return value
  1452. indicates failure)
  1453. @retval TRUE CPUID leaf fetch successfully.
  1454. @retval FALSE Error occurred while fetching CPUID leaf. Callers
  1455. should Status and Unsupported and handle
  1456. accordingly if they indicate a more precise
  1457. error condition.
  1458. **/
  1459. STATIC
  1460. BOOLEAN
  1461. GetCpuidFw (
  1462. IN OUT GHCB *Ghcb,
  1463. IN UINT32 EaxIn,
  1464. IN UINT32 EcxIn,
  1465. IN UINT64 XCr0,
  1466. IN OUT UINT32 *Eax,
  1467. IN OUT UINT32 *Ebx,
  1468. IN OUT UINT32 *Ecx,
  1469. IN OUT UINT32 *Edx,
  1470. IN OUT UINT64 *Status,
  1471. IN OUT BOOLEAN *Unsupported
  1472. )
  1473. {
  1474. SEV_SNP_CPUID_INFO *CpuidInfo;
  1475. BOOLEAN Found;
  1476. UINT32 Idx;
  1477. CpuidInfo = (SEV_SNP_CPUID_INFO *)(UINT64)PcdGet32 (PcdOvmfCpuidBase);
  1478. Found = FALSE;
  1479. for (Idx = 0; Idx < CpuidInfo->Count; Idx++) {
  1480. SEV_SNP_CPUID_FUNCTION *CpuidFn = &CpuidInfo->function[Idx];
  1481. if (CpuidFn->EaxIn != EaxIn) {
  1482. continue;
  1483. }
  1484. if (IsFunctionIndexed (CpuidFn->EaxIn) && (CpuidFn->EcxIn != EcxIn)) {
  1485. continue;
  1486. }
  1487. *Eax = CpuidFn->Eax;
  1488. *Ebx = CpuidFn->Ebx;
  1489. *Ecx = CpuidFn->Ecx;
  1490. *Edx = CpuidFn->Edx;
  1491. Found = TRUE;
  1492. break;
  1493. }
  1494. if (!Found) {
  1495. *Eax = *Ebx = *Ecx = *Edx = 0;
  1496. goto Out;
  1497. }
  1498. if (EaxIn == CPUID_VERSION_INFO) {
  1499. IA32_CR4 Cr4;
  1500. UINT32 Ebx2;
  1501. UINT32 Edx2;
  1502. if (!GetCpuidHyp (
  1503. Ghcb,
  1504. EaxIn,
  1505. EcxIn,
  1506. XCr0,
  1507. NULL,
  1508. &Ebx2,
  1509. NULL,
  1510. &Edx2,
  1511. Status,
  1512. Unsupported
  1513. ))
  1514. {
  1515. return FALSE;
  1516. }
  1517. /* initial APIC ID */
  1518. *Ebx = (*Ebx & 0x00FFFFFF) | (Ebx2 & 0xFF000000);
  1519. /* APIC enabled bit */
  1520. *Edx = (*Edx & ~BIT9) | (Edx2 & BIT9);
  1521. /* OSXSAVE enabled bit */
  1522. Cr4.UintN = AsmReadCr4 ();
  1523. *Ecx = (Cr4.Bits.OSXSAVE) ? (*Ecx & ~BIT27) | (*Ecx & BIT27)
  1524. : (*Ecx & ~BIT27);
  1525. } else if (EaxIn == CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS) {
  1526. IA32_CR4 Cr4;
  1527. Cr4.UintN = AsmReadCr4 ();
  1528. /* OSPKE enabled bit */
  1529. *Ecx = (Cr4.Bits.PKE) ? (*Ecx | BIT4) : (*Ecx & ~BIT4);
  1530. } else if (EaxIn == CPUID_EXTENDED_TOPOLOGY) {
  1531. if (!GetCpuidHyp (
  1532. Ghcb,
  1533. EaxIn,
  1534. EcxIn,
  1535. XCr0,
  1536. NULL,
  1537. NULL,
  1538. NULL,
  1539. Edx,
  1540. Status,
  1541. Unsupported
  1542. ))
  1543. {
  1544. return FALSE;
  1545. }
  1546. } else if ((EaxIn == CPUID_EXTENDED_STATE) && ((EcxIn == 0) || (EcxIn == 1))) {
  1547. MSR_IA32_XSS_REGISTER XssMsr;
  1548. BOOLEAN Compacted;
  1549. UINT32 XSaveSize;
  1550. XssMsr.Uint64 = 0;
  1551. Compacted = FALSE;
  1552. if (EcxIn == 1) {
  1553. /*
  1554. * The PPR and APM aren't clear on what size should be encoded in
  1555. * 0xD:0x1:EBX when compaction is not enabled by either XSAVEC or
  1556. * XSAVES, as these are generally fixed to 1 on real CPUs. Report
  1557. * this undefined case as an error.
  1558. */
  1559. if (!(*Eax & (BIT3 | BIT1))) {
  1560. /* (XSAVES | XSAVEC) */
  1561. return FALSE;
  1562. }
  1563. Compacted = TRUE;
  1564. XssMsr.Uint64 = AsmReadMsr64 (MSR_IA32_XSS);
  1565. }
  1566. if (!GetCpuidXSaveSize (
  1567. XCr0 | XssMsr.Uint64,
  1568. *Ebx,
  1569. &XSaveSize,
  1570. Compacted
  1571. ))
  1572. {
  1573. return FALSE;
  1574. }
  1575. *Ebx = XSaveSize;
  1576. } else if (EaxIn == 0x8000001E) {
  1577. UINT32 Ebx2;
  1578. UINT32 Ecx2;
  1579. /* extended APIC ID */
  1580. if (!GetCpuidHyp (
  1581. Ghcb,
  1582. EaxIn,
  1583. EcxIn,
  1584. XCr0,
  1585. Eax,
  1586. &Ebx2,
  1587. &Ecx2,
  1588. NULL,
  1589. Status,
  1590. Unsupported
  1591. ))
  1592. {
  1593. return FALSE;
  1594. }
  1595. /* compute ID */
  1596. *Ebx = (*Ebx & 0xFFFFFF00) | (Ebx2 & 0x000000FF);
  1597. /* node ID */
  1598. *Ecx = (*Ecx & 0xFFFFFF00) | (Ecx2 & 0x000000FF);
  1599. }
  1600. Out:
  1601. *Status = 0;
  1602. *Unsupported = FALSE;
  1603. return TRUE;
  1604. }
  1605. /**
  1606. Handle a CPUID event.
  1607. Use VMGEXIT instruction or CPUID table to handle a CPUID event.
  1608. @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
  1609. Block
  1610. @param[in, out] Regs x64 processor context
  1611. @param[in] InstructionData Instruction parsing context
  1612. @retval 0 Event handled successfully
  1613. @return New exception value to propagate
  1614. **/
  1615. STATIC
  1616. UINT64
  1617. CpuidExit (
  1618. IN OUT GHCB *Ghcb,
  1619. IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
  1620. IN SEV_ES_INSTRUCTION_DATA *InstructionData
  1621. )
  1622. {
  1623. BOOLEAN Unsupported;
  1624. UINT64 Status;
  1625. UINT32 EaxIn;
  1626. UINT32 EcxIn;
  1627. UINT64 XCr0;
  1628. UINT32 Eax;
  1629. UINT32 Ebx;
  1630. UINT32 Ecx;
  1631. UINT32 Edx;
  1632. EaxIn = (UINT32)(UINTN)Regs->Rax;
  1633. EcxIn = (UINT32)(UINTN)Regs->Rcx;
  1634. if (EaxIn == CPUID_EXTENDED_STATE) {
  1635. IA32_CR4 Cr4;
  1636. Cr4.UintN = AsmReadCr4 ();
  1637. Ghcb->SaveArea.XCr0 = (Cr4.Bits.OSXSAVE == 1) ? AsmXGetBv (0) : 1;
  1638. XCr0 = (Cr4.Bits.OSXSAVE == 1) ? AsmXGetBv (0) : 1;
  1639. }
  1640. if (SnpEnabled ()) {
  1641. if (!GetCpuidFw (
  1642. Ghcb,
  1643. EaxIn,
  1644. EcxIn,
  1645. XCr0,
  1646. &Eax,
  1647. &Ebx,
  1648. &Ecx,
  1649. &Edx,
  1650. &Status,
  1651. &Unsupported
  1652. ))
  1653. {
  1654. goto CpuidFail;
  1655. }
  1656. } else {
  1657. if (!GetCpuidHyp (
  1658. Ghcb,
  1659. EaxIn,
  1660. EcxIn,
  1661. XCr0,
  1662. &Eax,
  1663. &Ebx,
  1664. &Ecx,
  1665. &Edx,
  1666. &Status,
  1667. &Unsupported
  1668. ))
  1669. {
  1670. goto CpuidFail;
  1671. }
  1672. }
  1673. Regs->Rax = Eax;
  1674. Regs->Rbx = Ebx;
  1675. Regs->Rcx = Ecx;
  1676. Regs->Rdx = Edx;
  1677. return 0;
  1678. CpuidFail:
  1679. if (Unsupported) {
  1680. return UnsupportedExit (Ghcb, Regs, InstructionData);
  1681. }
  1682. return Status;
  1683. }
  1684. /**
  1685. Handle a RDPMC event.
  1686. Use the VMGEXIT instruction to handle a RDPMC event.
  1687. @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
  1688. Block
  1689. @param[in, out] Regs x64 processor context
  1690. @param[in] InstructionData Instruction parsing context
  1691. @retval 0 Event handled successfully
  1692. @return New exception value to propagate
  1693. **/
  1694. STATIC
  1695. UINT64
  1696. RdpmcExit (
  1697. IN OUT GHCB *Ghcb,
  1698. IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
  1699. IN SEV_ES_INSTRUCTION_DATA *InstructionData
  1700. )
  1701. {
  1702. UINT64 Status;
  1703. Ghcb->SaveArea.Rcx = Regs->Rcx;
  1704. VmgSetOffsetValid (Ghcb, GhcbRcx);
  1705. Status = VmgExit (Ghcb, SVM_EXIT_RDPMC, 0, 0);
  1706. if (Status != 0) {
  1707. return Status;
  1708. }
  1709. if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||
  1710. !VmgIsOffsetValid (Ghcb, GhcbRdx))
  1711. {
  1712. return UnsupportedExit (Ghcb, Regs, InstructionData);
  1713. }
  1714. Regs->Rax = Ghcb->SaveArea.Rax;
  1715. Regs->Rdx = Ghcb->SaveArea.Rdx;
  1716. return 0;
  1717. }
  1718. /**
  1719. Handle a RDTSC event.
  1720. Use the VMGEXIT instruction to handle a RDTSC event.
  1721. @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
  1722. Block
  1723. @param[in, out] Regs x64 processor context
  1724. @param[in] InstructionData Instruction parsing context
  1725. @retval 0 Event handled successfully
  1726. @return New exception value to propagate
  1727. **/
  1728. STATIC
  1729. UINT64
  1730. RdtscExit (
  1731. IN OUT GHCB *Ghcb,
  1732. IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
  1733. IN SEV_ES_INSTRUCTION_DATA *InstructionData
  1734. )
  1735. {
  1736. UINT64 Status;
  1737. Status = VmgExit (Ghcb, SVM_EXIT_RDTSC, 0, 0);
  1738. if (Status != 0) {
  1739. return Status;
  1740. }
  1741. if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||
  1742. !VmgIsOffsetValid (Ghcb, GhcbRdx))
  1743. {
  1744. return UnsupportedExit (Ghcb, Regs, InstructionData);
  1745. }
  1746. Regs->Rax = Ghcb->SaveArea.Rax;
  1747. Regs->Rdx = Ghcb->SaveArea.Rdx;
  1748. return 0;
  1749. }
  1750. /**
  1751. Handle a DR7 register write event.
  1752. Use the VMGEXIT instruction to handle a DR7 write event.
  1753. @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
  1754. Block
  1755. @param[in, out] Regs x64 processor context
  1756. @param[in] InstructionData Instruction parsing context
  1757. @retval 0 Event handled successfully
  1758. @return New exception value to propagate
  1759. **/
  1760. STATIC
  1761. UINT64
  1762. Dr7WriteExit (
  1763. IN OUT GHCB *Ghcb,
  1764. IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
  1765. IN SEV_ES_INSTRUCTION_DATA *InstructionData
  1766. )
  1767. {
  1768. SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;
  1769. SEV_ES_PER_CPU_DATA *SevEsData;
  1770. UINT64 *Register;
  1771. UINT64 Status;
  1772. Ext = &InstructionData->Ext;
  1773. SevEsData = (SEV_ES_PER_CPU_DATA *)(Ghcb + 1);
  1774. DecodeModRm (Regs, InstructionData);
  1775. //
  1776. // MOV DRn always treats MOD == 3 no matter how encoded
  1777. //
  1778. Register = GetRegisterPointer (Regs, Ext->ModRm.Rm);
  1779. //
  1780. // Using a value of 0 for ExitInfo1 means RAX holds the value
  1781. //
  1782. Ghcb->SaveArea.Rax = *Register;
  1783. VmgSetOffsetValid (Ghcb, GhcbRax);
  1784. Status = VmgExit (Ghcb, SVM_EXIT_DR7_WRITE, 0, 0);
  1785. if (Status != 0) {
  1786. return Status;
  1787. }
  1788. SevEsData->Dr7 = *Register;
  1789. SevEsData->Dr7Cached = 1;
  1790. return 0;
  1791. }
  1792. /**
  1793. Handle a DR7 register read event.
  1794. Use the VMGEXIT instruction to handle a DR7 read event.
  1795. @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
  1796. Block
  1797. @param[in, out] Regs x64 processor context
  1798. @param[in] InstructionData Instruction parsing context
  1799. @retval 0 Event handled successfully
  1800. **/
  1801. STATIC
  1802. UINT64
  1803. Dr7ReadExit (
  1804. IN OUT GHCB *Ghcb,
  1805. IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
  1806. IN SEV_ES_INSTRUCTION_DATA *InstructionData
  1807. )
  1808. {
  1809. SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;
  1810. SEV_ES_PER_CPU_DATA *SevEsData;
  1811. UINT64 *Register;
  1812. Ext = &InstructionData->Ext;
  1813. SevEsData = (SEV_ES_PER_CPU_DATA *)(Ghcb + 1);
  1814. DecodeModRm (Regs, InstructionData);
  1815. //
  1816. // MOV DRn always treats MOD == 3 no matter how encoded
  1817. //
  1818. Register = GetRegisterPointer (Regs, Ext->ModRm.Rm);
  1819. //
  1820. // If there is a cached valued for DR7, return that. Otherwise return the
  1821. // DR7 standard reset value of 0x400 (no debug breakpoints set).
  1822. //
  1823. *Register = (SevEsData->Dr7Cached == 1) ? SevEsData->Dr7 : 0x400;
  1824. return 0;
  1825. }
  1826. /**
  1827. Handle a #VC exception.
  1828. Performs the necessary processing to handle a #VC exception.
  1829. @param[in, out] Ghcb Pointer to the GHCB
  1830. @param[in, out] ExceptionType Pointer to an EFI_EXCEPTION_TYPE to be set
  1831. as value to use on error.
  1832. @param[in, out] SystemContext Pointer to EFI_SYSTEM_CONTEXT
  1833. @retval EFI_SUCCESS Exception handled
  1834. @retval EFI_UNSUPPORTED #VC not supported, (new) exception value to
  1835. propagate provided
  1836. @retval EFI_PROTOCOL_ERROR #VC handling failed, (new) exception value to
  1837. propagate provided
  1838. **/
  1839. EFI_STATUS
  1840. EFIAPI
  1841. InternalVmgExitHandleVc (
  1842. IN OUT GHCB *Ghcb,
  1843. IN OUT EFI_EXCEPTION_TYPE *ExceptionType,
  1844. IN OUT EFI_SYSTEM_CONTEXT SystemContext
  1845. )
  1846. {
  1847. EFI_SYSTEM_CONTEXT_X64 *Regs;
  1848. NAE_EXIT NaeExit;
  1849. SEV_ES_INSTRUCTION_DATA InstructionData;
  1850. UINT64 ExitCode, Status;
  1851. EFI_STATUS VcRet;
  1852. BOOLEAN InterruptState;
  1853. VcRet = EFI_SUCCESS;
  1854. Regs = SystemContext.SystemContextX64;
  1855. VmgInit (Ghcb, &InterruptState);
  1856. ExitCode = Regs->ExceptionData;
  1857. switch (ExitCode) {
  1858. case SVM_EXIT_DR7_READ:
  1859. NaeExit = Dr7ReadExit;
  1860. break;
  1861. case SVM_EXIT_DR7_WRITE:
  1862. NaeExit = Dr7WriteExit;
  1863. break;
  1864. case SVM_EXIT_RDTSC:
  1865. NaeExit = RdtscExit;
  1866. break;
  1867. case SVM_EXIT_RDPMC:
  1868. NaeExit = RdpmcExit;
  1869. break;
  1870. case SVM_EXIT_CPUID:
  1871. NaeExit = CpuidExit;
  1872. break;
  1873. case SVM_EXIT_INVD:
  1874. NaeExit = InvdExit;
  1875. break;
  1876. case SVM_EXIT_IOIO_PROT:
  1877. NaeExit = IoioExit;
  1878. break;
  1879. case SVM_EXIT_MSR:
  1880. NaeExit = MsrExit;
  1881. break;
  1882. case SVM_EXIT_VMMCALL:
  1883. NaeExit = VmmCallExit;
  1884. break;
  1885. case SVM_EXIT_RDTSCP:
  1886. NaeExit = RdtscpExit;
  1887. break;
  1888. case SVM_EXIT_WBINVD:
  1889. NaeExit = WbinvdExit;
  1890. break;
  1891. case SVM_EXIT_MONITOR:
  1892. NaeExit = MonitorExit;
  1893. break;
  1894. case SVM_EXIT_MWAIT:
  1895. NaeExit = MwaitExit;
  1896. break;
  1897. case SVM_EXIT_NPF:
  1898. NaeExit = MmioExit;
  1899. break;
  1900. default:
  1901. NaeExit = UnsupportedExit;
  1902. }
  1903. InitInstructionData (&InstructionData, Ghcb, Regs);
  1904. Status = NaeExit (Ghcb, Regs, &InstructionData);
  1905. if (Status == 0) {
  1906. Regs->Rip += InstructionLength (&InstructionData);
  1907. } else {
  1908. GHCB_EVENT_INJECTION Event;
  1909. Event.Uint64 = Status;
  1910. if (Event.Elements.ErrorCodeValid != 0) {
  1911. Regs->ExceptionData = Event.Elements.ErrorCode;
  1912. } else {
  1913. Regs->ExceptionData = 0;
  1914. }
  1915. *ExceptionType = Event.Elements.Vector;
  1916. VcRet = EFI_PROTOCOL_ERROR;
  1917. }
  1918. VmgDone (Ghcb, InterruptState);
  1919. return VcRet;
  1920. }
  1921. /**
  1922. Routine to allow ASSERT from within #VC.
  1923. @param[in, out] SevEsData Pointer to the per-CPU data
  1924. **/
  1925. VOID
  1926. EFIAPI
  1927. VmgExitIssueAssert (
  1928. IN OUT SEV_ES_PER_CPU_DATA *SevEsData
  1929. )
  1930. {
  1931. //
  1932. // Progress will be halted, so set VcCount to allow for ASSERT output
  1933. // to be seen.
  1934. //
  1935. SevEsData->VcCount = 0;
  1936. ASSERT (FALSE);
  1937. CpuDeadLoop ();
  1938. }