ArchExceptionHandler.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. /** @file
  2. x64 CPU Exception Handler.
  3. Copyright (c) 2012 - 2019, Intel Corporation. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include "CpuExceptionCommon.h"
  7. /**
  8. Return address map of exception handler template so that C code can generate
  9. exception tables.
  10. @param IdtEntry Pointer to IDT entry to be updated.
  11. @param InterruptHandler IDT handler value.
  12. **/
  13. VOID
  14. ArchUpdateIdtEntry (
  15. OUT IA32_IDT_GATE_DESCRIPTOR *IdtEntry,
  16. IN UINTN InterruptHandler
  17. )
  18. {
  19. IdtEntry->Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler;
  20. IdtEntry->Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16);
  21. IdtEntry->Bits.OffsetUpper = (UINT32)((UINTN)InterruptHandler >> 32);
  22. IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
  23. }
  24. /**
  25. Read IDT handler value from IDT entry.
  26. @param IdtEntry Pointer to IDT entry to be read.
  27. **/
  28. UINTN
  29. ArchGetIdtHandler (
  30. IN IA32_IDT_GATE_DESCRIPTOR *IdtEntry
  31. )
  32. {
  33. return IdtEntry->Bits.OffsetLow + (((UINTN)IdtEntry->Bits.OffsetHigh) << 16) +
  34. (((UINTN)IdtEntry->Bits.OffsetUpper) << 32);
  35. }
  36. /**
  37. Save CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.
  38. @param[in] ExceptionType Exception type.
  39. @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.
  40. @param[in] ExceptionHandlerData Pointer to exception handler data.
  41. **/
  42. VOID
  43. ArchSaveExceptionContext (
  44. IN UINTN ExceptionType,
  45. IN EFI_SYSTEM_CONTEXT SystemContext,
  46. IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData
  47. )
  48. {
  49. IA32_EFLAGS32 Eflags;
  50. RESERVED_VECTORS_DATA *ReservedVectors;
  51. ReservedVectors = ExceptionHandlerData->ReservedVectors;
  52. //
  53. // Save Exception context in global variable in first entry of the exception handler.
  54. // So when original exception handler returns to the new exception handler (second entry),
  55. // the Eflags/Cs/Eip/ExceptionData can be used.
  56. //
  57. ReservedVectors[ExceptionType].OldSs = SystemContext.SystemContextX64->Ss;
  58. ReservedVectors[ExceptionType].OldSp = SystemContext.SystemContextX64->Rsp;
  59. ReservedVectors[ExceptionType].OldFlags = SystemContext.SystemContextX64->Rflags;
  60. ReservedVectors[ExceptionType].OldCs = SystemContext.SystemContextX64->Cs;
  61. ReservedVectors[ExceptionType].OldIp = SystemContext.SystemContextX64->Rip;
  62. ReservedVectors[ExceptionType].ExceptionData = SystemContext.SystemContextX64->ExceptionData;
  63. //
  64. // Clear IF flag to avoid old IDT handler enable interrupt by IRET
  65. //
  66. Eflags.UintN = SystemContext.SystemContextX64->Rflags;
  67. Eflags.Bits.IF = 0;
  68. SystemContext.SystemContextX64->Rflags = Eflags.UintN;
  69. //
  70. // Modify the EIP in stack, then old IDT handler will return to HookAfterStubBegin.
  71. //
  72. SystemContext.SystemContextX64->Rip = (UINTN)ReservedVectors[ExceptionType].HookAfterStubHeaderCode;
  73. }
  74. /**
  75. Restore CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.
  76. @param[in] ExceptionType Exception type.
  77. @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.
  78. @param[in] ExceptionHandlerData Pointer to exception handler data.
  79. **/
  80. VOID
  81. ArchRestoreExceptionContext (
  82. IN UINTN ExceptionType,
  83. IN EFI_SYSTEM_CONTEXT SystemContext,
  84. IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData
  85. )
  86. {
  87. RESERVED_VECTORS_DATA *ReservedVectors;
  88. ReservedVectors = ExceptionHandlerData->ReservedVectors;
  89. SystemContext.SystemContextX64->Ss = ReservedVectors[ExceptionType].OldSs;
  90. SystemContext.SystemContextX64->Rsp = ReservedVectors[ExceptionType].OldSp;
  91. SystemContext.SystemContextX64->Rflags = ReservedVectors[ExceptionType].OldFlags;
  92. SystemContext.SystemContextX64->Cs = ReservedVectors[ExceptionType].OldCs;
  93. SystemContext.SystemContextX64->Rip = ReservedVectors[ExceptionType].OldIp;
  94. SystemContext.SystemContextX64->ExceptionData = ReservedVectors[ExceptionType].ExceptionData;
  95. }
  96. /**
  97. Setup separate stack for given exceptions.
  98. @param[in] StackSwitchData Pointer to data required for setuping up
  99. stack switch.
  100. @retval EFI_SUCCESS The exceptions have been successfully
  101. initialized with new stack.
  102. @retval EFI_INVALID_PARAMETER StackSwitchData contains invalid content.
  103. **/
  104. EFI_STATUS
  105. ArchSetupExceptionStack (
  106. IN CPU_EXCEPTION_INIT_DATA *StackSwitchData
  107. )
  108. {
  109. IA32_DESCRIPTOR Gdtr;
  110. IA32_DESCRIPTOR Idtr;
  111. IA32_IDT_GATE_DESCRIPTOR *IdtTable;
  112. IA32_TSS_DESCRIPTOR *TssDesc;
  113. IA32_TASK_STATE_SEGMENT *Tss;
  114. UINTN StackTop;
  115. UINTN Index;
  116. UINTN Vector;
  117. UINTN TssBase;
  118. UINTN GdtSize;
  119. if ((StackSwitchData == NULL) ||
  120. (StackSwitchData->Ia32.Revision != CPU_EXCEPTION_INIT_DATA_REV) ||
  121. (StackSwitchData->X64.KnownGoodStackTop == 0) ||
  122. (StackSwitchData->X64.KnownGoodStackSize == 0) ||
  123. (StackSwitchData->X64.StackSwitchExceptions == NULL) ||
  124. (StackSwitchData->X64.StackSwitchExceptionNumber == 0) ||
  125. (StackSwitchData->X64.StackSwitchExceptionNumber > CPU_EXCEPTION_NUM) ||
  126. (StackSwitchData->X64.GdtTable == NULL) ||
  127. (StackSwitchData->X64.IdtTable == NULL) ||
  128. (StackSwitchData->X64.ExceptionTssDesc == NULL) ||
  129. (StackSwitchData->X64.ExceptionTss == NULL))
  130. {
  131. return EFI_INVALID_PARAMETER;
  132. }
  133. //
  134. // The caller is responsible for that the GDT table, no matter the existing
  135. // one or newly allocated, has enough space to hold descriptors for exception
  136. // task-state segments.
  137. //
  138. if (((UINTN)StackSwitchData->X64.GdtTable & (IA32_GDT_ALIGNMENT - 1)) != 0) {
  139. return EFI_INVALID_PARAMETER;
  140. }
  141. if ((UINTN)StackSwitchData->X64.ExceptionTssDesc < (UINTN)(StackSwitchData->X64.GdtTable)) {
  142. return EFI_INVALID_PARAMETER;
  143. }
  144. if (((UINTN)StackSwitchData->X64.ExceptionTssDesc + StackSwitchData->X64.ExceptionTssDescSize) >
  145. ((UINTN)(StackSwitchData->X64.GdtTable) + StackSwitchData->X64.GdtTableSize))
  146. {
  147. return EFI_INVALID_PARAMETER;
  148. }
  149. //
  150. // One task gate descriptor and one task-state segment are needed.
  151. //
  152. if (StackSwitchData->X64.ExceptionTssDescSize < sizeof (IA32_TSS_DESCRIPTOR)) {
  153. return EFI_INVALID_PARAMETER;
  154. }
  155. if (StackSwitchData->X64.ExceptionTssSize < sizeof (IA32_TASK_STATE_SEGMENT)) {
  156. return EFI_INVALID_PARAMETER;
  157. }
  158. //
  159. // Interrupt stack table supports only 7 vectors.
  160. //
  161. TssDesc = StackSwitchData->X64.ExceptionTssDesc;
  162. Tss = StackSwitchData->X64.ExceptionTss;
  163. if (StackSwitchData->X64.StackSwitchExceptionNumber > ARRAY_SIZE (Tss->IST)) {
  164. return EFI_INVALID_PARAMETER;
  165. }
  166. //
  167. // Initialize new GDT table and/or IDT table, if any
  168. //
  169. AsmReadIdtr (&Idtr);
  170. AsmReadGdtr (&Gdtr);
  171. GdtSize = (UINTN)TssDesc + sizeof (IA32_TSS_DESCRIPTOR) -
  172. (UINTN)(StackSwitchData->X64.GdtTable);
  173. if ((UINTN)StackSwitchData->X64.GdtTable != Gdtr.Base) {
  174. CopyMem (StackSwitchData->X64.GdtTable, (VOID *)Gdtr.Base, Gdtr.Limit + 1);
  175. Gdtr.Base = (UINTN)StackSwitchData->X64.GdtTable;
  176. Gdtr.Limit = (UINT16)GdtSize - 1;
  177. }
  178. if ((UINTN)StackSwitchData->X64.IdtTable != Idtr.Base) {
  179. Idtr.Base = (UINTN)StackSwitchData->X64.IdtTable;
  180. }
  181. if (StackSwitchData->X64.IdtTableSize > 0) {
  182. Idtr.Limit = (UINT16)(StackSwitchData->X64.IdtTableSize - 1);
  183. }
  184. //
  185. // Fixup current task descriptor. Task-state segment for current task will
  186. // be filled by processor during task switching.
  187. //
  188. TssBase = (UINTN)Tss;
  189. TssDesc->Uint128.Uint64 = 0;
  190. TssDesc->Uint128.Uint64_1 = 0;
  191. TssDesc->Bits.LimitLow = sizeof (IA32_TASK_STATE_SEGMENT) - 1;
  192. TssDesc->Bits.BaseLow = (UINT16)TssBase;
  193. TssDesc->Bits.BaseMidl = (UINT8)(TssBase >> 16);
  194. TssDesc->Bits.Type = IA32_GDT_TYPE_TSS;
  195. TssDesc->Bits.P = 1;
  196. TssDesc->Bits.LimitHigh = 0;
  197. TssDesc->Bits.BaseMidh = (UINT8)(TssBase >> 24);
  198. TssDesc->Bits.BaseHigh = (UINT32)(TssBase >> 32);
  199. //
  200. // Fixup exception task descriptor and task-state segment
  201. //
  202. ZeroMem (Tss, sizeof (*Tss));
  203. StackTop = StackSwitchData->X64.KnownGoodStackTop - CPU_STACK_ALIGNMENT;
  204. StackTop = (UINTN)ALIGN_POINTER (StackTop, CPU_STACK_ALIGNMENT);
  205. IdtTable = StackSwitchData->X64.IdtTable;
  206. for (Index = 0; Index < StackSwitchData->X64.StackSwitchExceptionNumber; ++Index) {
  207. //
  208. // Fixup IST
  209. //
  210. Tss->IST[Index] = StackTop;
  211. StackTop -= StackSwitchData->X64.KnownGoodStackSize;
  212. //
  213. // Set the IST field to enable corresponding IST
  214. //
  215. Vector = StackSwitchData->X64.StackSwitchExceptions[Index];
  216. if ((Vector >= CPU_EXCEPTION_NUM) ||
  217. (Vector >= (Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR)))
  218. {
  219. continue;
  220. }
  221. IdtTable[Vector].Bits.Reserved_0 = (UINT8)(Index + 1);
  222. }
  223. //
  224. // Publish GDT
  225. //
  226. AsmWriteGdtr (&Gdtr);
  227. //
  228. // Load current task
  229. //
  230. AsmWriteTr ((UINT16)((UINTN)StackSwitchData->X64.ExceptionTssDesc - Gdtr.Base));
  231. //
  232. // Publish IDT
  233. //
  234. AsmWriteIdtr (&Idtr);
  235. return EFI_SUCCESS;
  236. }
  237. /**
  238. Display CPU information.
  239. @param ExceptionType Exception type.
  240. @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
  241. **/
  242. VOID
  243. EFIAPI
  244. DumpCpuContext (
  245. IN EFI_EXCEPTION_TYPE ExceptionType,
  246. IN EFI_SYSTEM_CONTEXT SystemContext
  247. )
  248. {
  249. InternalPrintMessage (
  250. "!!!! X64 Exception Type - %02x(%a) CPU Apic ID - %08x !!!!\n",
  251. ExceptionType,
  252. GetExceptionNameStr (ExceptionType),
  253. GetApicId ()
  254. );
  255. if ((mErrorCodeFlag & (1 << ExceptionType)) != 0) {
  256. InternalPrintMessage (
  257. "ExceptionData - %016lx",
  258. SystemContext.SystemContextX64->ExceptionData
  259. );
  260. if (ExceptionType == EXCEPT_IA32_PAGE_FAULT) {
  261. InternalPrintMessage (
  262. " I:%x R:%x U:%x W:%x P:%x PK:%x SS:%x SGX:%x",
  263. (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_ID) != 0,
  264. (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_RSVD) != 0,
  265. (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_US) != 0,
  266. (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_WR) != 0,
  267. (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_P) != 0,
  268. (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_PK) != 0,
  269. (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_SS) != 0,
  270. (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_SGX) != 0
  271. );
  272. }
  273. InternalPrintMessage ("\n");
  274. }
  275. InternalPrintMessage (
  276. "RIP - %016lx, CS - %016lx, RFLAGS - %016lx\n",
  277. SystemContext.SystemContextX64->Rip,
  278. SystemContext.SystemContextX64->Cs,
  279. SystemContext.SystemContextX64->Rflags
  280. );
  281. InternalPrintMessage (
  282. "RAX - %016lx, RCX - %016lx, RDX - %016lx\n",
  283. SystemContext.SystemContextX64->Rax,
  284. SystemContext.SystemContextX64->Rcx,
  285. SystemContext.SystemContextX64->Rdx
  286. );
  287. InternalPrintMessage (
  288. "RBX - %016lx, RSP - %016lx, RBP - %016lx\n",
  289. SystemContext.SystemContextX64->Rbx,
  290. SystemContext.SystemContextX64->Rsp,
  291. SystemContext.SystemContextX64->Rbp
  292. );
  293. InternalPrintMessage (
  294. "RSI - %016lx, RDI - %016lx\n",
  295. SystemContext.SystemContextX64->Rsi,
  296. SystemContext.SystemContextX64->Rdi
  297. );
  298. InternalPrintMessage (
  299. "R8 - %016lx, R9 - %016lx, R10 - %016lx\n",
  300. SystemContext.SystemContextX64->R8,
  301. SystemContext.SystemContextX64->R9,
  302. SystemContext.SystemContextX64->R10
  303. );
  304. InternalPrintMessage (
  305. "R11 - %016lx, R12 - %016lx, R13 - %016lx\n",
  306. SystemContext.SystemContextX64->R11,
  307. SystemContext.SystemContextX64->R12,
  308. SystemContext.SystemContextX64->R13
  309. );
  310. InternalPrintMessage (
  311. "R14 - %016lx, R15 - %016lx\n",
  312. SystemContext.SystemContextX64->R14,
  313. SystemContext.SystemContextX64->R15
  314. );
  315. InternalPrintMessage (
  316. "DS - %016lx, ES - %016lx, FS - %016lx\n",
  317. SystemContext.SystemContextX64->Ds,
  318. SystemContext.SystemContextX64->Es,
  319. SystemContext.SystemContextX64->Fs
  320. );
  321. InternalPrintMessage (
  322. "GS - %016lx, SS - %016lx\n",
  323. SystemContext.SystemContextX64->Gs,
  324. SystemContext.SystemContextX64->Ss
  325. );
  326. InternalPrintMessage (
  327. "CR0 - %016lx, CR2 - %016lx, CR3 - %016lx\n",
  328. SystemContext.SystemContextX64->Cr0,
  329. SystemContext.SystemContextX64->Cr2,
  330. SystemContext.SystemContextX64->Cr3
  331. );
  332. InternalPrintMessage (
  333. "CR4 - %016lx, CR8 - %016lx\n",
  334. SystemContext.SystemContextX64->Cr4,
  335. SystemContext.SystemContextX64->Cr8
  336. );
  337. InternalPrintMessage (
  338. "DR0 - %016lx, DR1 - %016lx, DR2 - %016lx\n",
  339. SystemContext.SystemContextX64->Dr0,
  340. SystemContext.SystemContextX64->Dr1,
  341. SystemContext.SystemContextX64->Dr2
  342. );
  343. InternalPrintMessage (
  344. "DR3 - %016lx, DR6 - %016lx, DR7 - %016lx\n",
  345. SystemContext.SystemContextX64->Dr3,
  346. SystemContext.SystemContextX64->Dr6,
  347. SystemContext.SystemContextX64->Dr7
  348. );
  349. InternalPrintMessage (
  350. "GDTR - %016lx %016lx, LDTR - %016lx\n",
  351. SystemContext.SystemContextX64->Gdtr[0],
  352. SystemContext.SystemContextX64->Gdtr[1],
  353. SystemContext.SystemContextX64->Ldtr
  354. );
  355. InternalPrintMessage (
  356. "IDTR - %016lx %016lx, TR - %016lx\n",
  357. SystemContext.SystemContextX64->Idtr[0],
  358. SystemContext.SystemContextX64->Idtr[1],
  359. SystemContext.SystemContextX64->Tr
  360. );
  361. InternalPrintMessage (
  362. "FXSAVE_STATE - %016lx\n",
  363. &SystemContext.SystemContextX64->FxSaveState
  364. );
  365. }
  366. /**
  367. Display CPU information.
  368. @param ExceptionType Exception type.
  369. @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
  370. **/
  371. VOID
  372. DumpImageAndCpuContent (
  373. IN EFI_EXCEPTION_TYPE ExceptionType,
  374. IN EFI_SYSTEM_CONTEXT SystemContext
  375. )
  376. {
  377. DumpCpuContext (ExceptionType, SystemContext);
  378. //
  379. // Dump module image base and module entry point by RIP
  380. //
  381. if ((ExceptionType == EXCEPT_IA32_PAGE_FAULT) &&
  382. ((SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_ID) != 0))
  383. {
  384. //
  385. // The RIP in SystemContext could not be used
  386. // if it is page fault with I/D set.
  387. //
  388. DumpModuleImageInfo ((*(UINTN *)(UINTN)SystemContext.SystemContextX64->Rsp));
  389. } else {
  390. DumpModuleImageInfo (SystemContext.SystemContextX64->Rip);
  391. }
  392. }