ArchExceptionHandler.c 15 KB

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