Processor.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682
  1. /** @file
  2. Processor specific parts of the GDB stub
  3. Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include <GdbStubInternal.h>
  7. #include <Library/CacheMaintenanceLib.h>
  8. #include <Library/PrintLib.h>
  9. //
  10. // Array of exception types that need to be hooked by the debugger
  11. // (efi, gdb) //efi number
  12. //
  13. EFI_EXCEPTION_TYPE_ENTRY gExceptionType[] = {
  14. { EXCEPT_ARM_SOFTWARE_INTERRUPT, GDB_SIGTRAP }
  15. // { EXCEPT_ARM_UNDEFINED_INSTRUCTION, GDB_SIGTRAP },
  16. // { EXCEPT_ARM_PREFETCH_ABORT, GDB_SIGTRAP },
  17. // { EXCEPT_ARM_DATA_ABORT, GDB_SIGEMT },
  18. // { EXCEPT_ARM_RESERVED, GDB_SIGILL }
  19. };
  20. UINTN gRegisterOffsets[] = {
  21. OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, R0),
  22. OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, R1),
  23. OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, R2),
  24. OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, R3),
  25. OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, R4),
  26. OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, R5),
  27. OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, R6),
  28. OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, R7),
  29. OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, R8),
  30. OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, R9),
  31. OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, R10),
  32. OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, R11),
  33. OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, R12),
  34. OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, SP),
  35. OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, LR),
  36. OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, PC),
  37. 0x00000F01, // f0
  38. 0x00000F02,
  39. 0x00000F03,
  40. 0x00000F11, // f1
  41. 0x00000F12,
  42. 0x00000F13,
  43. 0x00000F21, // f2
  44. 0x00000F22,
  45. 0x00000F23,
  46. 0x00000F31, // f3
  47. 0x00000F32,
  48. 0x00000F33,
  49. 0x00000F41, // f4
  50. 0x00000F42,
  51. 0x00000F43,
  52. 0x00000F51, // f5
  53. 0x00000F52,
  54. 0x00000F53,
  55. 0x00000F61, // f6
  56. 0x00000F62,
  57. 0x00000F63,
  58. 0x00000F71, // f7
  59. 0x00000F72,
  60. 0x00000F73,
  61. 0x00000FFF, // fps
  62. OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, CPSR)
  63. };
  64. /**
  65. Return the number of entries in the gExceptionType[]
  66. @retval UINTN, the number of entries in the gExceptionType[] array.
  67. **/
  68. UINTN
  69. MaxEfiException (
  70. VOID
  71. )
  72. {
  73. return sizeof (gExceptionType) / sizeof (EFI_EXCEPTION_TYPE_ENTRY);
  74. }
  75. /**
  76. Return the number of entries in the gRegisters[]
  77. @retval UINTN, the number of entries (registers) in the gRegisters[] array.
  78. **/
  79. UINTN
  80. MaxRegisterCount (
  81. VOID
  82. )
  83. {
  84. return sizeof (gRegisterOffsets) / sizeof (UINTN);
  85. }
  86. /**
  87. Check to see if the ISA is supported.
  88. ISA = Instruction Set Architecture
  89. @retval TRUE if Isa is supported
  90. **/
  91. BOOLEAN
  92. CheckIsa (
  93. IN EFI_INSTRUCTION_SET_ARCHITECTURE Isa
  94. )
  95. {
  96. if (Isa == IsaArm) {
  97. return TRUE;
  98. } else {
  99. return FALSE;
  100. }
  101. }
  102. /**
  103. This takes in the register number and the System Context, and returns a pointer to the RegNumber-th register in gdb ordering
  104. It is, by default, set to find the register pointer of the ARM member
  105. @param SystemContext Register content at time of the exception
  106. @param RegNumber The register to which we want to find a pointer
  107. @retval the pointer to the RegNumber-th pointer
  108. **/
  109. UINTN *
  110. FindPointerToRegister (
  111. IN EFI_SYSTEM_CONTEXT SystemContext,
  112. IN UINTN RegNumber
  113. )
  114. {
  115. UINT8 *TempPtr;
  116. ASSERT (gRegisterOffsets[RegNumber] < 0xF00);
  117. TempPtr = ((UINT8 *)SystemContext.SystemContextArm) + gRegisterOffsets[RegNumber];
  118. return (UINT32 *)TempPtr;
  119. }
  120. /**
  121. Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr
  122. @param SystemContext Register content at time of the exception
  123. @param RegNumber the number of the register that we want to read
  124. @param OutBufPtr pointer to the output buffer's end. the new data will be added from this point on.
  125. @retval the pointer to the next character of the output buffer that is available to be written on.
  126. **/
  127. CHAR8 *
  128. BasicReadRegister (
  129. IN EFI_SYSTEM_CONTEXT SystemContext,
  130. IN UINTN RegNumber,
  131. IN CHAR8 *OutBufPtr
  132. )
  133. {
  134. UINTN RegSize;
  135. CHAR8 Char;
  136. if (gRegisterOffsets[RegNumber] > 0xF00) {
  137. AsciiSPrint (OutBufPtr, 9, "00000000");
  138. OutBufPtr += 8;
  139. return OutBufPtr;
  140. }
  141. RegSize = 0;
  142. while (RegSize < 32) {
  143. Char = mHexToStr[(UINT8)((*FindPointerToRegister (SystemContext, RegNumber) >> (RegSize+4)) & 0xf)];
  144. if ((Char >= 'A') && (Char <= 'F')) {
  145. Char = Char - 'A' + 'a';
  146. }
  147. *OutBufPtr++ = Char;
  148. Char = mHexToStr[(UINT8)((*FindPointerToRegister (SystemContext, RegNumber) >> RegSize) & 0xf)];
  149. if ((Char >= 'A') && (Char <= 'F')) {
  150. Char = Char - 'A' + 'a';
  151. }
  152. *OutBufPtr++ = Char;
  153. RegSize = RegSize + 8;
  154. }
  155. return OutBufPtr;
  156. }
  157. /**
  158. Reads the n-th register's value into an output buffer and sends it as a packet
  159. @param SystemContext Register content at time of the exception
  160. @param InBuffer Pointer to the input buffer received from gdb server
  161. **/
  162. VOID
  163. ReadNthRegister (
  164. IN EFI_SYSTEM_CONTEXT SystemContext,
  165. IN CHAR8 *InBuffer
  166. )
  167. {
  168. UINTN RegNumber;
  169. CHAR8 OutBuffer[9]; // 1 reg=8 hex chars, and the end '\0' (escape seq)
  170. CHAR8 *OutBufPtr; // pointer to the output buffer
  171. RegNumber = AsciiStrHexToUintn (&InBuffer[1]);
  172. if (RegNumber >= MaxRegisterCount ()) {
  173. SendError (GDB_EINVALIDREGNUM);
  174. return;
  175. }
  176. OutBufPtr = OutBuffer;
  177. OutBufPtr = BasicReadRegister (SystemContext, RegNumber, OutBufPtr);
  178. *OutBufPtr = '\0'; // the end of the buffer
  179. SendPacket (OutBuffer);
  180. }
  181. /**
  182. Reads the general registers into an output buffer and sends it as a packet
  183. @param SystemContext Register content at time of the exception
  184. **/
  185. VOID
  186. EFIAPI
  187. ReadGeneralRegisters (
  188. IN EFI_SYSTEM_CONTEXT SystemContext
  189. )
  190. {
  191. UINTN Index;
  192. CHAR8 *OutBuffer;
  193. CHAR8 *OutBufPtr;
  194. UINTN RegisterCount = MaxRegisterCount ();
  195. // It is not safe to allocate pool here....
  196. OutBuffer = AllocatePool ((RegisterCount * 8) + 1); // 8 bytes per register in string format plus a null to terminate
  197. OutBufPtr = OutBuffer;
  198. for (Index = 0; Index < RegisterCount; Index++) {
  199. OutBufPtr = BasicReadRegister (SystemContext, Index, OutBufPtr);
  200. }
  201. *OutBufPtr = '\0';
  202. SendPacket (OutBuffer);
  203. FreePool (OutBuffer);
  204. }
  205. /**
  206. Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr
  207. @param SystemContext Register content at time of the exception
  208. @param RegNumber the number of the register that we want to write
  209. @param InBufPtr pointer to the output buffer. the new data will be extracted from the input buffer from this point on.
  210. @retval the pointer to the next character of the input buffer that can be used
  211. **/
  212. CHAR8
  213. *
  214. BasicWriteRegister (
  215. IN EFI_SYSTEM_CONTEXT SystemContext,
  216. IN UINTN RegNumber,
  217. IN CHAR8 *InBufPtr
  218. )
  219. {
  220. UINTN RegSize;
  221. UINTN TempValue; // the value transferred from a hex char
  222. UINT32 NewValue; // the new value of the RegNumber-th Register
  223. if (gRegisterOffsets[RegNumber] > 0xF00) {
  224. return InBufPtr + 8;
  225. }
  226. NewValue = 0;
  227. RegSize = 0;
  228. while (RegSize < 32) {
  229. TempValue = HexCharToInt (*InBufPtr++);
  230. if ((INTN)TempValue < 0) {
  231. SendError (GDB_EBADMEMDATA);
  232. return NULL;
  233. }
  234. NewValue += (TempValue << (RegSize+4));
  235. TempValue = HexCharToInt (*InBufPtr++);
  236. if ((INTN)TempValue < 0) {
  237. SendError (GDB_EBADMEMDATA);
  238. return NULL;
  239. }
  240. NewValue += (TempValue << RegSize);
  241. RegSize = RegSize + 8;
  242. }
  243. *(FindPointerToRegister (SystemContext, RegNumber)) = NewValue;
  244. return InBufPtr;
  245. }
  246. /** ‘P n...=r...’
  247. Writes the new value of n-th register received into the input buffer to the n-th register
  248. @param SystemContext Register content at time of the exception
  249. @param InBuffer Pointer to the input buffer received from gdb server
  250. **/
  251. VOID
  252. WriteNthRegister (
  253. IN EFI_SYSTEM_CONTEXT SystemContext,
  254. IN CHAR8 *InBuffer
  255. )
  256. {
  257. UINTN RegNumber;
  258. CHAR8 RegNumBuffer[MAX_REG_NUM_BUF_SIZE]; // put the 'n..' part of the message into this array
  259. CHAR8 *RegNumBufPtr;
  260. CHAR8 *InBufPtr; // pointer to the input buffer
  261. // find the register number to write
  262. InBufPtr = &InBuffer[1];
  263. RegNumBufPtr = RegNumBuffer;
  264. while (*InBufPtr != '=') {
  265. *RegNumBufPtr++ = *InBufPtr++;
  266. }
  267. *RegNumBufPtr = '\0';
  268. RegNumber = AsciiStrHexToUintn (RegNumBuffer);
  269. // check if this is a valid Register Number
  270. if (RegNumber >= MaxRegisterCount ()) {
  271. SendError (GDB_EINVALIDREGNUM);
  272. return;
  273. }
  274. InBufPtr++; // skips the '=' character
  275. BasicWriteRegister (SystemContext, RegNumber, InBufPtr);
  276. SendSuccess ();
  277. }
  278. /** ‘G XX...’
  279. Writes the new values received into the input buffer to the general registers
  280. @param SystemContext Register content at time of the exception
  281. @param InBuffer Pointer to the input buffer received from gdb server
  282. **/
  283. VOID
  284. EFIAPI
  285. WriteGeneralRegisters (
  286. IN EFI_SYSTEM_CONTEXT SystemContext,
  287. IN CHAR8 *InBuffer
  288. )
  289. {
  290. UINTN i;
  291. CHAR8 *InBufPtr; /// pointer to the input buffer
  292. UINTN MinLength;
  293. UINTN RegisterCount = MaxRegisterCount ();
  294. MinLength = (RegisterCount * 8) + 1; // 'G' plus the registers in ASCII format
  295. if (AsciiStrLen (InBuffer) < MinLength) {
  296. // Bad message. Message is not the right length
  297. SendError (GDB_EBADBUFSIZE);
  298. return;
  299. }
  300. InBufPtr = &InBuffer[1];
  301. // Read the new values for the registers from the input buffer to an array, NewValueArray.
  302. // The values in the array are in the gdb ordering
  303. for (i = 0; i < RegisterCount; i++) {
  304. InBufPtr = BasicWriteRegister (SystemContext, i, InBufPtr);
  305. }
  306. SendSuccess ();
  307. }
  308. // What about Thumb?
  309. // Use SWI 0xdbdbdb as the debug instruction
  310. #define GDB_ARM_BKPT 0xefdbdbdb
  311. BOOLEAN mSingleStepActive = FALSE;
  312. UINT32 mSingleStepPC;
  313. UINT32 mSingleStepData;
  314. UINTN mSingleStepDataSize;
  315. typedef struct {
  316. LIST_ENTRY Link;
  317. UINT64 Signature;
  318. UINT32 Address;
  319. UINT32 Instruction;
  320. } ARM_SOFTWARE_BREAKPOINT;
  321. #define ARM_SOFTWARE_BREAKPOINT_SIGNATURE SIGNATURE_64('A', 'R', 'M', 'B', 'R', 'K', 'P', 'T')
  322. #define ARM_SOFTWARE_BREAKPOINT_FROM_LINK(a) CR(a, ARM_SOFTWARE_BREAKPOINT, Link, ARM_SOFTWARE_BREAKPOINT_SIGNATURE)
  323. LIST_ENTRY BreakpointList;
  324. /**
  325. Insert Single Step in the SystemContext
  326. @param SystemContext Register content at time of the exception
  327. **/
  328. VOID
  329. AddSingleStep (
  330. IN EFI_SYSTEM_CONTEXT SystemContext
  331. )
  332. {
  333. if (mSingleStepActive) {
  334. // Currently don't support nesting
  335. return;
  336. }
  337. mSingleStepActive = TRUE;
  338. mSingleStepPC = SystemContext.SystemContextArm->PC;
  339. mSingleStepDataSize = sizeof (UINT32);
  340. mSingleStepData = (*(UINT32 *)mSingleStepPC);
  341. *(UINT32 *)mSingleStepPC = GDB_ARM_BKPT;
  342. if (*(UINT32 *)mSingleStepPC != GDB_ARM_BKPT) {
  343. // For some reason our breakpoint did not take
  344. mSingleStepActive = FALSE;
  345. }
  346. InvalidateInstructionCacheRange ((VOID *)mSingleStepPC, mSingleStepDataSize);
  347. // DEBUG((DEBUG_ERROR, "AddSingleStep at 0x%08x (was: 0x%08x is:0x%08x)\n", SystemContext.SystemContextArm->PC, mSingleStepData, *(UINT32 *)mSingleStepPC));
  348. }
  349. /**
  350. Remove Single Step in the SystemContext
  351. @param SystemContext Register content at time of the exception
  352. **/
  353. VOID
  354. RemoveSingleStep (
  355. IN EFI_SYSTEM_CONTEXT SystemContext
  356. )
  357. {
  358. if (!mSingleStepActive) {
  359. return;
  360. }
  361. if (mSingleStepDataSize == sizeof (UINT16)) {
  362. *(UINT16 *)mSingleStepPC = (UINT16)mSingleStepData;
  363. } else {
  364. // DEBUG((DEBUG_ERROR, "RemoveSingleStep at 0x%08x (was: 0x%08x is:0x%08x)\n", SystemContext.SystemContextArm->PC, *(UINT32 *)mSingleStepPC, mSingleStepData));
  365. *(UINT32 *)mSingleStepPC = mSingleStepData;
  366. }
  367. InvalidateInstructionCacheRange ((VOID *)mSingleStepPC, mSingleStepDataSize);
  368. mSingleStepActive = FALSE;
  369. }
  370. /**
  371. Continue. addr is Address to resume. If addr is omitted, resume at current
  372. Address.
  373. @param SystemContext Register content at time of the exception
  374. **/
  375. VOID
  376. EFIAPI
  377. ContinueAtAddress (
  378. IN EFI_SYSTEM_CONTEXT SystemContext,
  379. IN CHAR8 *PacketData
  380. )
  381. {
  382. if (PacketData[1] != '\0') {
  383. SystemContext.SystemContextArm->PC = AsciiStrHexToUintn (&PacketData[1]);
  384. }
  385. }
  386. /** ‘s [addr ]’
  387. Single step. addr is the Address at which to resume. If addr is omitted, resume
  388. at same Address.
  389. @param SystemContext Register content at time of the exception
  390. **/
  391. VOID
  392. EFIAPI
  393. SingleStep (
  394. IN EFI_SYSTEM_CONTEXT SystemContext,
  395. IN CHAR8 *PacketData
  396. )
  397. {
  398. SendNotSupported ();
  399. }
  400. UINTN
  401. GetBreakpointDataAddress (
  402. IN EFI_SYSTEM_CONTEXT SystemContext,
  403. IN UINTN BreakpointNumber
  404. )
  405. {
  406. return 0;
  407. }
  408. UINTN
  409. GetBreakpointDetected (
  410. IN EFI_SYSTEM_CONTEXT SystemContext
  411. )
  412. {
  413. return 0;
  414. }
  415. BREAK_TYPE
  416. GetBreakpointType (
  417. IN EFI_SYSTEM_CONTEXT SystemContext,
  418. IN UINTN BreakpointNumber
  419. )
  420. {
  421. return NotSupported;
  422. }
  423. ARM_SOFTWARE_BREAKPOINT *
  424. SearchBreakpointList (
  425. IN UINT32 Address
  426. )
  427. {
  428. LIST_ENTRY *Current;
  429. ARM_SOFTWARE_BREAKPOINT *Breakpoint;
  430. Current = GetFirstNode (&BreakpointList);
  431. while (!IsNull (&BreakpointList, Current)) {
  432. Breakpoint = ARM_SOFTWARE_BREAKPOINT_FROM_LINK (Current);
  433. if (Address == Breakpoint->Address) {
  434. return Breakpoint;
  435. }
  436. Current = GetNextNode (&BreakpointList, Current);
  437. }
  438. return NULL;
  439. }
  440. VOID
  441. SetBreakpoint (
  442. IN UINT32 Address
  443. )
  444. {
  445. ARM_SOFTWARE_BREAKPOINT *Breakpoint;
  446. Breakpoint = SearchBreakpointList (Address);
  447. if (Breakpoint != NULL) {
  448. return;
  449. }
  450. // create and fill breakpoint structure
  451. Breakpoint = AllocatePool (sizeof (ARM_SOFTWARE_BREAKPOINT));
  452. Breakpoint->Signature = ARM_SOFTWARE_BREAKPOINT_SIGNATURE;
  453. Breakpoint->Address = Address;
  454. Breakpoint->Instruction = *(UINT32 *)Address;
  455. // Add it to the list
  456. InsertTailList (&BreakpointList, &Breakpoint->Link);
  457. // Insert the software breakpoint
  458. *(UINT32 *)Address = GDB_ARM_BKPT;
  459. InvalidateInstructionCacheRange ((VOID *)Address, 4);
  460. // DEBUG((DEBUG_ERROR, "SetBreakpoint at 0x%08x (was: 0x%08x is:0x%08x)\n", Address, Breakpoint->Instruction, *(UINT32 *)Address));
  461. }
  462. VOID
  463. ClearBreakpoint (
  464. IN UINT32 Address
  465. )
  466. {
  467. ARM_SOFTWARE_BREAKPOINT *Breakpoint;
  468. Breakpoint = SearchBreakpointList (Address);
  469. if (Breakpoint == NULL) {
  470. return;
  471. }
  472. // Add it to the list
  473. RemoveEntryList (&Breakpoint->Link);
  474. // Restore the original instruction
  475. *(UINT32 *)Address = Breakpoint->Instruction;
  476. InvalidateInstructionCacheRange ((VOID *)Address, 4);
  477. // DEBUG((DEBUG_ERROR, "ClearBreakpoint at 0x%08x (was: 0x%08x is:0x%08x)\n", Address, GDB_ARM_BKPT, *(UINT32 *)Address));
  478. FreePool (Breakpoint);
  479. }
  480. VOID
  481. EFIAPI
  482. InsertBreakPoint (
  483. IN EFI_SYSTEM_CONTEXT SystemContext,
  484. IN CHAR8 *PacketData
  485. )
  486. {
  487. UINTN Type;
  488. UINTN Address;
  489. UINTN Length;
  490. UINTN ErrorCode;
  491. ErrorCode = ParseBreakpointPacket (PacketData, &Type, &Address, &Length);
  492. if (ErrorCode > 0) {
  493. SendError ((UINT8)ErrorCode);
  494. return;
  495. }
  496. switch (Type) {
  497. case 0: // Software breakpoint
  498. break;
  499. default:
  500. DEBUG ((DEBUG_ERROR, "Insert breakpoint default: %x\n", Type));
  501. SendError (GDB_EINVALIDBRKPOINTTYPE);
  502. return;
  503. }
  504. SetBreakpoint (Address);
  505. SendSuccess ();
  506. }
  507. VOID
  508. EFIAPI
  509. RemoveBreakPoint (
  510. IN EFI_SYSTEM_CONTEXT SystemContext,
  511. IN CHAR8 *PacketData
  512. )
  513. {
  514. UINTN Type;
  515. UINTN Address;
  516. UINTN Length;
  517. UINTN ErrorCode;
  518. // Parse breakpoint packet data
  519. ErrorCode = ParseBreakpointPacket (PacketData, &Type, &Address, &Length);
  520. if (ErrorCode > 0) {
  521. SendError ((UINT8)ErrorCode);
  522. return;
  523. }
  524. switch (Type) {
  525. case 0: // Software breakpoint
  526. break;
  527. default:
  528. SendError (GDB_EINVALIDBRKPOINTTYPE);
  529. return;
  530. }
  531. ClearBreakpoint (Address);
  532. SendSuccess ();
  533. }
  534. VOID
  535. InitializeProcessor (
  536. VOID
  537. )
  538. {
  539. // Initialize breakpoint list
  540. InitializeListHead (&BreakpointList);
  541. }
  542. BOOLEAN
  543. ValidateAddress (
  544. IN VOID *Address
  545. )
  546. {
  547. if ((UINT32)Address < 0x80000000) {
  548. return FALSE;
  549. } else {
  550. return TRUE;
  551. }
  552. }
  553. BOOLEAN
  554. ValidateException (
  555. IN EFI_EXCEPTION_TYPE ExceptionType,
  556. IN OUT EFI_SYSTEM_CONTEXT SystemContext
  557. )
  558. {
  559. UINT32 ExceptionAddress;
  560. UINT32 Instruction;
  561. // Is it a debugger SWI?
  562. ExceptionAddress = SystemContext.SystemContextArm->PC -= 4;
  563. Instruction = *(UINT32 *)ExceptionAddress;
  564. if (Instruction != GDB_ARM_BKPT) {
  565. return FALSE;
  566. }
  567. // Special for SWI-based exception handling. SWI sets up the context
  568. // to return to the instruction following the SWI instruction - NOT what we want
  569. // for a debugger!
  570. SystemContext.SystemContextArm->PC = ExceptionAddress;
  571. return TRUE;
  572. }