Processor.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945
  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. //
  8. // Array of exception types that need to be hooked by the debugger
  9. //
  10. EFI_EXCEPTION_TYPE_ENTRY gExceptionType[] = {
  11. { EXCEPT_X64_DIVIDE_ERROR, GDB_SIGFPE },
  12. { EXCEPT_X64_DEBUG, GDB_SIGTRAP },
  13. { EXCEPT_X64_NMI, GDB_SIGEMT },
  14. { EXCEPT_X64_BREAKPOINT, GDB_SIGTRAP },
  15. { EXCEPT_X64_OVERFLOW, GDB_SIGSEGV },
  16. { EXCEPT_X64_BOUND, GDB_SIGSEGV },
  17. { EXCEPT_X64_INVALID_OPCODE, GDB_SIGILL },
  18. { EXCEPT_X64_DOUBLE_FAULT, GDB_SIGEMT },
  19. { EXCEPT_X64_STACK_FAULT, GDB_SIGSEGV },
  20. { EXCEPT_X64_GP_FAULT, GDB_SIGSEGV },
  21. { EXCEPT_X64_PAGE_FAULT, GDB_SIGSEGV },
  22. { EXCEPT_X64_FP_ERROR, GDB_SIGEMT },
  23. { EXCEPT_X64_ALIGNMENT_CHECK, GDB_SIGEMT },
  24. { EXCEPT_X64_MACHINE_CHECK, GDB_SIGEMT }
  25. };
  26. // The offsets of registers SystemContextX64.
  27. // The fields in the array are in the gdb ordering.
  28. // HAVE TO DOUBLE-CHECK THE ORDER of the 24 regs
  29. //
  30. UINTN gRegisterOffsets[] = {
  31. OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Rax),
  32. OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Rcx),
  33. OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Rdx),
  34. OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Rbx),
  35. OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Rsp),
  36. OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Rbp),
  37. OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Rsi),
  38. OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Rdi),
  39. OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Rip),
  40. OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Rflags),
  41. OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Cs),
  42. OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Ss),
  43. OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Ds),
  44. OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Es),
  45. OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Fs),
  46. OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Gs),
  47. OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, R8),
  48. OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, R9),
  49. OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, R10),
  50. OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, R11),
  51. OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, R12),
  52. OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, R13),
  53. OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, R14),
  54. OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, R15)
  55. };
  56. /**
  57. Return the number of entries in the gExceptionType[]
  58. @retval UINTN, the number of entries in the gExceptionType[] array.
  59. **/
  60. UINTN
  61. MaxEfiException (
  62. VOID
  63. )
  64. {
  65. return sizeof (gExceptionType)/sizeof (EFI_EXCEPTION_TYPE_ENTRY);
  66. }
  67. /**
  68. Return the number of entries in the gRegisters[]
  69. @retval UINTN, the number of entries (registers) in the gRegisters[] array.
  70. **/
  71. UINTN
  72. MaxRegisterCount (
  73. VOID
  74. )
  75. {
  76. return sizeof (gRegisterOffsets)/sizeof (UINTN);
  77. }
  78. /**
  79. Check to see if the ISA is supported.
  80. ISA = Instruction Set Architecture
  81. @retval TRUE if Isa is supported
  82. **/
  83. BOOLEAN
  84. CheckIsa (
  85. IN EFI_INSTRUCTION_SET_ARCHITECTURE Isa
  86. )
  87. {
  88. return (BOOLEAN)(Isa == IsaX64);
  89. }
  90. /**
  91. This takes in the register number and the System Context, and returns a pointer to the RegNumber-th register in gdb ordering
  92. It is, by default, set to find the register pointer of the X64 member
  93. @param SystemContext Register content at time of the exception
  94. @param RegNumber The register to which we want to find a pointer
  95. @retval the pointer to the RegNumber-th pointer
  96. **/
  97. UINTN *
  98. FindPointerToRegister (
  99. IN EFI_SYSTEM_CONTEXT SystemContext,
  100. IN UINTN RegNumber
  101. )
  102. {
  103. UINT8 *TempPtr;
  104. TempPtr = ((UINT8 *)SystemContext.SystemContextX64) + gRegisterOffsets[RegNumber];
  105. return (UINTN *)TempPtr;
  106. }
  107. /**
  108. Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr
  109. @param SystemContext Register content at time of the exception
  110. @param RegNumber the number of the register that we want to read
  111. @param OutBufPtr pointer to the output buffer's end. the new data will be added from this point on.
  112. @retval the pointer to the next character of the output buffer that is available to be written on.
  113. **/
  114. CHAR8 *
  115. BasicReadRegister (
  116. IN EFI_SYSTEM_CONTEXT SystemContext,
  117. IN UINTN RegNumber,
  118. IN CHAR8 *OutBufPtr
  119. )
  120. {
  121. UINTN RegSize;
  122. RegSize = 0;
  123. while (RegSize < 64) {
  124. *OutBufPtr++ = mHexToStr[((*FindPointerToRegister (SystemContext, RegNumber) >> (RegSize+4)) & 0xf)];
  125. *OutBufPtr++ = mHexToStr[((*FindPointerToRegister (SystemContext, RegNumber) >> RegSize) & 0xf)];
  126. RegSize = RegSize + 8;
  127. }
  128. return OutBufPtr;
  129. }
  130. /** ‘p n’
  131. Reads the n-th register's value into an output buffer and sends it as a packet
  132. @param SystemContext Register content at time of the exception
  133. @param InBuffer Pointer to the input buffer received from gdb server
  134. **/
  135. VOID
  136. ReadNthRegister (
  137. IN EFI_SYSTEM_CONTEXT SystemContext,
  138. IN CHAR8 *InBuffer
  139. )
  140. {
  141. UINTN RegNumber;
  142. CHAR8 OutBuffer[17]; // 1 reg=16 hex chars, and the end '\0' (escape seq)
  143. CHAR8 *OutBufPtr; // pointer to the output buffer
  144. RegNumber = AsciiStrHexToUintn (&InBuffer[1]);
  145. if ((RegNumber < 0) || (RegNumber >= MaxRegisterCount ())) {
  146. SendError (GDB_EINVALIDREGNUM);
  147. return;
  148. }
  149. OutBufPtr = OutBuffer;
  150. OutBufPtr = BasicReadRegister (SystemContext, RegNumber, OutBufPtr);
  151. *OutBufPtr = '\0'; // the end of the buffer
  152. SendPacket (OutBuffer);
  153. }
  154. /** ‘g’
  155. Reads the general registers into an output buffer and sends it as a packet
  156. @param SystemContext Register content at time of the exception
  157. **/
  158. VOID
  159. EFIAPI
  160. ReadGeneralRegisters (
  161. IN EFI_SYSTEM_CONTEXT SystemContext
  162. )
  163. {
  164. UINTN i;
  165. CHAR8 OutBuffer[385]; // 24 regs, 16 hex chars each, and the end '\0' (escape seq)
  166. CHAR8 *OutBufPtr; // pointer to the output buffer
  167. OutBufPtr = OutBuffer;
  168. for (i = 0; i < MaxRegisterCount (); i++) {
  169. // there are only 24 registers to read
  170. OutBufPtr = BasicReadRegister (SystemContext, i, OutBufPtr);
  171. }
  172. *OutBufPtr = '\0'; // the end of the buffer
  173. SendPacket (OutBuffer);
  174. }
  175. /**
  176. Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr
  177. @param SystemContext Register content at time of the exception
  178. @param RegNumber the number of the register that we want to write
  179. @param InBufPtr pointer to the output buffer. the new data will be extracted from the input buffer from this point on.
  180. @retval the pointer to the next character of the input buffer that can be used
  181. **/
  182. CHAR8 *
  183. BasicWriteRegister (
  184. IN EFI_SYSTEM_CONTEXT SystemContext,
  185. IN UINTN RegNumber,
  186. IN CHAR8 *InBufPtr
  187. )
  188. {
  189. UINTN RegSize;
  190. UINTN TempValue; // the value transferred from a hex char
  191. UINT64 NewValue; // the new value of the RegNumber-th Register
  192. NewValue = 0;
  193. RegSize = 0;
  194. while (RegSize < 64) {
  195. TempValue = HexCharToInt (*InBufPtr++);
  196. if (TempValue < 0) {
  197. SendError (GDB_EBADMEMDATA);
  198. return NULL;
  199. }
  200. NewValue += (TempValue << (RegSize+4));
  201. TempValue = HexCharToInt (*InBufPtr++);
  202. if (TempValue < 0) {
  203. SendError (GDB_EBADMEMDATA);
  204. return NULL;
  205. }
  206. NewValue += (TempValue << RegSize);
  207. RegSize = RegSize + 8;
  208. }
  209. *(FindPointerToRegister (SystemContext, RegNumber)) = NewValue;
  210. return InBufPtr;
  211. }
  212. /** ‘P n...=r...’
  213. Writes the new value of n-th register received into the input buffer to the n-th register
  214. @param SystemContext Register content at time of the exception
  215. @param InBuffer Pointer to the input buffer received from gdb server
  216. **/
  217. VOID
  218. EFIAPI
  219. WriteNthRegister (
  220. IN EFI_SYSTEM_CONTEXT SystemContext,
  221. IN CHAR8 *InBuffer
  222. )
  223. {
  224. UINTN RegNumber;
  225. CHAR8 RegNumBuffer[MAX_REG_NUM_BUF_SIZE]; // put the 'n..' part of the message into this array
  226. CHAR8 *RegNumBufPtr;
  227. CHAR8 *InBufPtr; // pointer to the input buffer
  228. // find the register number to write
  229. InBufPtr = &InBuffer[1];
  230. RegNumBufPtr = RegNumBuffer;
  231. while (*InBufPtr != '=') {
  232. *RegNumBufPtr++ = *InBufPtr++;
  233. }
  234. *RegNumBufPtr = '\0';
  235. RegNumber = AsciiStrHexToUintn (RegNumBuffer);
  236. // check if this is a valid Register Number
  237. if ((RegNumber < 0) || (RegNumber >= MaxRegisterCount ())) {
  238. SendError (GDB_EINVALIDREGNUM);
  239. return;
  240. }
  241. InBufPtr++; // skips the '=' character
  242. BasicWriteRegister (SystemContext, RegNumber, InBufPtr);
  243. SendSuccess ();
  244. }
  245. /** ‘G XX...’
  246. Writes the new values received into the input buffer to the general registers
  247. @param SystemContext Register content at time of the exception
  248. @param InBuffer Pointer to the input buffer received from gdb server
  249. **/
  250. VOID
  251. EFIAPI
  252. WriteGeneralRegisters (
  253. IN EFI_SYSTEM_CONTEXT SystemContext,
  254. IN CHAR8 *InBuffer
  255. )
  256. {
  257. UINTN i;
  258. CHAR8 *InBufPtr; /// pointer to the input buffer
  259. // check to see if the buffer is the right size which is
  260. // 1 (for 'G') + 16 (for 16 registers) * 8 ( for 8 hex chars each) = 385
  261. if (AsciiStrLen (InBuffer) != 385) {
  262. // 24 regs, 16 hex chars each, and the end '\0' (escape seq)
  263. // Bad message. Message is not the right length
  264. SendError (GDB_EBADBUFSIZE);
  265. return;
  266. }
  267. InBufPtr = &InBuffer[1];
  268. // Read the new values for the registers from the input buffer to an array, NewValueArray.
  269. // The values in the array are in the gdb ordering
  270. for (i = 0; i < MaxRegisterCount (); i++) {
  271. // there are only 16 registers to write
  272. InBufPtr = BasicWriteRegister (SystemContext, i, InBufPtr);
  273. }
  274. SendSuccess ();
  275. }
  276. /**
  277. Insert Single Step in the SystemContext
  278. @param SystemContext Register content at time of the exception
  279. **/
  280. VOID
  281. AddSingleStep (
  282. IN EFI_SYSTEM_CONTEXT SystemContext
  283. )
  284. {
  285. SystemContext.SystemContextX64->Rflags |= TF_BIT; // Setting the TF bit.
  286. }
  287. /**
  288. Remove Single Step in the SystemContext
  289. @param SystemContext Register content at time of the exception
  290. **/
  291. VOID
  292. RemoveSingleStep (
  293. IN EFI_SYSTEM_CONTEXT SystemContext
  294. )
  295. {
  296. SystemContext.SystemContextX64->Rflags &= ~TF_BIT; // clearing the TF bit.
  297. }
  298. /** ‘c [addr ]’
  299. Continue. addr is Address to resume. If addr is omitted, resume at current
  300. Address.
  301. @param SystemContext Register content at time of the exception
  302. **/
  303. VOID
  304. EFIAPI
  305. ContinueAtAddress (
  306. IN EFI_SYSTEM_CONTEXT SystemContext,
  307. IN CHAR8 *PacketData
  308. )
  309. {
  310. if (PacketData[1] != '\0') {
  311. SystemContext.SystemContextX64->Rip = AsciiStrHexToUintn (&PacketData[1]);
  312. }
  313. }
  314. /** ‘s [addr ]’
  315. Single step. addr is the Address at which to resume. If addr is omitted, resume
  316. at same Address.
  317. @param SystemContext Register content at time of the exception
  318. **/
  319. VOID
  320. EFIAPI
  321. SingleStep (
  322. IN EFI_SYSTEM_CONTEXT SystemContext,
  323. IN CHAR8 *PacketData
  324. )
  325. {
  326. if (PacketData[1] != '\0') {
  327. SystemContext.SystemContextX64->Rip = AsciiStrHexToUintn (&PacketData[1]);
  328. }
  329. AddSingleStep (SystemContext);
  330. }
  331. /**
  332. Returns breakpoint data address from DR0-DR3 based on the input breakpoint
  333. number
  334. @param SystemContext Register content at time of the exception
  335. @param BreakpointNumber Breakpoint number
  336. @retval Address Data address from DR0-DR3 based on the
  337. breakpoint number.
  338. **/
  339. UINTN
  340. GetBreakpointDataAddress (
  341. IN EFI_SYSTEM_CONTEXT SystemContext,
  342. IN UINTN BreakpointNumber
  343. )
  344. {
  345. UINTN Address;
  346. if (BreakpointNumber == 1) {
  347. Address = SystemContext.SystemContextIa32->Dr0;
  348. } else if (BreakpointNumber == 2) {
  349. Address = SystemContext.SystemContextIa32->Dr1;
  350. } else if (BreakpointNumber == 3) {
  351. Address = SystemContext.SystemContextIa32->Dr2;
  352. } else if (BreakpointNumber == 4) {
  353. Address = SystemContext.SystemContextIa32->Dr3;
  354. } else {
  355. Address = 0;
  356. }
  357. return Address;
  358. }
  359. /**
  360. Returns currently detected breakpoint value based on the register
  361. DR6 B0-B3 field.
  362. If no breakpoint is detected then it returns 0.
  363. @param SystemContext Register content at time of the exception
  364. @retval {1-4} Currently detected breakpoint value
  365. @retval 0 No breakpoint detected.
  366. **/
  367. UINTN
  368. GetBreakpointDetected (
  369. IN EFI_SYSTEM_CONTEXT SystemContext
  370. )
  371. {
  372. IA32_DR6 Dr6;
  373. UINTN BreakpointNumber;
  374. Dr6.UintN = SystemContext.SystemContextIa32->Dr6;
  375. if (Dr6.Bits.B0 == 1) {
  376. BreakpointNumber = 1;
  377. } else if (Dr6.Bits.B1 == 1) {
  378. BreakpointNumber = 2;
  379. } else if (Dr6.Bits.B2 == 1) {
  380. BreakpointNumber = 3;
  381. } else if (Dr6.Bits.B3 == 1) {
  382. BreakpointNumber = 4;
  383. } else {
  384. BreakpointNumber = 0; // No breakpoint detected
  385. }
  386. return BreakpointNumber;
  387. }
  388. /**
  389. Returns Breakpoint type (InstructionExecution, DataWrite, DataRead
  390. or DataReadWrite) based on the Breakpoint number
  391. @param SystemContext Register content at time of the exception
  392. @param BreakpointNumber Breakpoint number
  393. @retval BREAK_TYPE Breakpoint type value read from register DR7 RWn
  394. field. For unknown value, it returns NotSupported.
  395. **/
  396. BREAK_TYPE
  397. GetBreakpointType (
  398. IN EFI_SYSTEM_CONTEXT SystemContext,
  399. IN UINTN BreakpointNumber
  400. )
  401. {
  402. IA32_DR7 Dr7;
  403. BREAK_TYPE Type = NotSupported; // Default is NotSupported type
  404. Dr7.UintN = SystemContext.SystemContextIa32->Dr7;
  405. if (BreakpointNumber == 1) {
  406. Type = (BREAK_TYPE)Dr7.Bits.RW0;
  407. } else if (BreakpointNumber == 2) {
  408. Type = (BREAK_TYPE)Dr7.Bits.RW1;
  409. } else if (BreakpointNumber == 3) {
  410. Type = (BREAK_TYPE)Dr7.Bits.RW2;
  411. } else if (BreakpointNumber == 4) {
  412. Type = (BREAK_TYPE)Dr7.Bits.RW3;
  413. }
  414. return Type;
  415. }
  416. /**
  417. Parses Length and returns the length which DR7 LENn field accepts.
  418. For example: If we receive 1-Byte length then we should return 0.
  419. Zero gets written to DR7 LENn field.
  420. @param Length Breakpoint length in Bytes (1 byte, 2 byte, 4 byte)
  421. @retval Length Appropriate converted values which DR7 LENn field accepts.
  422. **/
  423. UINTN
  424. ConvertLengthData (
  425. IN UINTN Length
  426. )
  427. {
  428. if (Length == 1) {
  429. // 1-Byte length
  430. return 0;
  431. } else if (Length == 2) {
  432. // 2-Byte length
  433. return 1;
  434. } else if (Length == 4) {
  435. // 4-Byte length
  436. return 3;
  437. } else {
  438. // Undefined or 8-byte length
  439. return 2;
  440. }
  441. }
  442. /**
  443. Finds the next free debug register. If all the registers are occupied then
  444. EFI_OUT_OF_RESOURCES is returned.
  445. @param SystemContext Register content at time of the exception
  446. @param Register Register value (0 - 3 for the first free debug register)
  447. @retval EFI_STATUS Appropriate status value.
  448. **/
  449. EFI_STATUS
  450. FindNextFreeDebugRegister (
  451. IN EFI_SYSTEM_CONTEXT SystemContext,
  452. OUT UINTN *Register
  453. )
  454. {
  455. IA32_DR7 Dr7;
  456. Dr7.UintN = SystemContext.SystemContextIa32->Dr7;
  457. if (Dr7.Bits.G0 == 0) {
  458. *Register = 0;
  459. } else if (Dr7.Bits.G1 == 0) {
  460. *Register = 1;
  461. } else if (Dr7.Bits.G2 == 0) {
  462. *Register = 2;
  463. } else if (Dr7.Bits.G3 == 0) {
  464. *Register = 3;
  465. } else {
  466. return EFI_OUT_OF_RESOURCES;
  467. }
  468. return EFI_SUCCESS;
  469. }
  470. /**
  471. Enables the debug register. Writes Address value to appropriate DR0-3 register.
  472. Sets LENn, Gn, RWn bits in DR7 register.
  473. @param SystemContext Register content at time of the exception
  474. @param Register Register value (0 - 3)
  475. @param Address Breakpoint address value
  476. @param Type Breakpoint type (Instruction, Data write,
  477. Data read or write etc.)
  478. @retval EFI_STATUS Appropriate status value.
  479. **/
  480. EFI_STATUS
  481. EnableDebugRegister (
  482. IN EFI_SYSTEM_CONTEXT SystemContext,
  483. IN UINTN Register,
  484. IN UINTN Address,
  485. IN UINTN Length,
  486. IN UINTN Type
  487. )
  488. {
  489. IA32_DR7 Dr7;
  490. // Convert length data
  491. Length = ConvertLengthData (Length);
  492. // For Instruction execution, length should be 0
  493. // (Ref. Intel reference manual 18.2.4)
  494. if ((Type == 0) && (Length != 0)) {
  495. return EFI_INVALID_PARAMETER;
  496. }
  497. // Hardware doesn't support ReadWatch (z3 packet) type. GDB can handle
  498. // software breakpoint. We should send empty packet in both these cases.
  499. if ((Type == (BREAK_TYPE)DataRead) ||
  500. (Type == (BREAK_TYPE)SoftwareBreakpoint))
  501. {
  502. return EFI_UNSUPPORTED;
  503. }
  504. // Read DR7 so appropriate Gn, RWn and LENn bits can be modified.
  505. Dr7.UintN = SystemContext.SystemContextIa32->Dr7;
  506. if (Register == 0) {
  507. SystemContext.SystemContextIa32->Dr0 = Address;
  508. Dr7.Bits.G0 = 1;
  509. Dr7.Bits.RW0 = Type;
  510. Dr7.Bits.LEN0 = Length;
  511. } else if (Register == 1) {
  512. SystemContext.SystemContextIa32->Dr1 = Address;
  513. Dr7.Bits.G1 = 1;
  514. Dr7.Bits.RW1 = Type;
  515. Dr7.Bits.LEN1 = Length;
  516. } else if (Register == 2) {
  517. SystemContext.SystemContextIa32->Dr2 = Address;
  518. Dr7.Bits.G2 = 1;
  519. Dr7.Bits.RW2 = Type;
  520. Dr7.Bits.LEN2 = Length;
  521. } else if (Register == 3) {
  522. SystemContext.SystemContextIa32->Dr3 = Address;
  523. Dr7.Bits.G3 = 1;
  524. Dr7.Bits.RW3 = Type;
  525. Dr7.Bits.LEN3 = Length;
  526. } else {
  527. return EFI_INVALID_PARAMETER;
  528. }
  529. // Update Dr7 with appropriate Gn, RWn and LENn bits
  530. SystemContext.SystemContextIa32->Dr7 = Dr7.UintN;
  531. return EFI_SUCCESS;
  532. }
  533. /**
  534. Returns register number 0 - 3 for the matching debug register.
  535. This function compares incoming Address, Type, Length and
  536. if there is a match then it returns the appropriate register number.
  537. In case of mismatch, function returns EFI_NOT_FOUND message.
  538. @param SystemContext Register content at time of the exception
  539. @param Address Breakpoint address value
  540. @param Length Breakpoint length value
  541. @param Type Breakpoint type (Instruction, Data write, Data read
  542. or write etc.)
  543. @param Register Register value to be returned
  544. @retval EFI_STATUS Appropriate status value.
  545. **/
  546. EFI_STATUS
  547. FindMatchingDebugRegister (
  548. IN EFI_SYSTEM_CONTEXT SystemContext,
  549. IN UINTN Address,
  550. IN UINTN Length,
  551. IN UINTN Type,
  552. OUT UINTN *Register
  553. )
  554. {
  555. IA32_DR7 Dr7;
  556. // Hardware doesn't support ReadWatch (z3 packet) type. GDB can handle
  557. // software breakpoint. We should send empty packet in both these cases.
  558. if ((Type == (BREAK_TYPE)DataRead) ||
  559. (Type == (BREAK_TYPE)SoftwareBreakpoint))
  560. {
  561. return EFI_UNSUPPORTED;
  562. }
  563. // Convert length data
  564. Length = ConvertLengthData (Length);
  565. Dr7.UintN = SystemContext.SystemContextIa32->Dr7;
  566. if ((Dr7.Bits.G0 == 1) &&
  567. (Dr7.Bits.LEN0 == Length) &&
  568. (Dr7.Bits.RW0 == Type) &&
  569. (Address == SystemContext.SystemContextIa32->Dr0))
  570. {
  571. *Register = 0;
  572. } else if ((Dr7.Bits.G1 == 1) &&
  573. (Dr7.Bits.LEN1 == Length) &&
  574. (Dr7.Bits.RW1 == Type) &&
  575. (Address == SystemContext.SystemContextIa32->Dr1))
  576. {
  577. *Register = 1;
  578. } else if ((Dr7.Bits.G2 == 1) &&
  579. (Dr7.Bits.LEN2 == Length) &&
  580. (Dr7.Bits.RW2 == Type) &&
  581. (Address == SystemContext.SystemContextIa32->Dr2))
  582. {
  583. *Register = 2;
  584. } else if ((Dr7.Bits.G3 == 1) &&
  585. (Dr7.Bits.LEN3 == Length) &&
  586. (Dr7.Bits.RW3 == Type) &&
  587. (Address == SystemContext.SystemContextIa32->Dr3))
  588. {
  589. *Register = 3;
  590. } else {
  591. Print ((CHAR16 *)L"No match found..\n");
  592. return EFI_NOT_FOUND;
  593. }
  594. return EFI_SUCCESS;
  595. }
  596. /**
  597. Disables the particular debug register.
  598. @param SystemContext Register content at time of the exception
  599. @param Register Register to be disabled
  600. @retval EFI_STATUS Appropriate status value.
  601. **/
  602. EFI_STATUS
  603. DisableDebugRegister (
  604. IN EFI_SYSTEM_CONTEXT SystemContext,
  605. IN UINTN Register
  606. )
  607. {
  608. IA32_DR7 Dr7;
  609. UINTN Address = 0;
  610. // Read DR7 register so appropriate Gn, RWn and LENn bits can be turned off.
  611. Dr7.UintN = SystemContext.SystemContextIa32->Dr7;
  612. if (Register == 0) {
  613. SystemContext.SystemContextIa32->Dr0 = Address;
  614. Dr7.Bits.G0 = 0;
  615. Dr7.Bits.RW0 = 0;
  616. Dr7.Bits.LEN0 = 0;
  617. } else if (Register == 1) {
  618. SystemContext.SystemContextIa32->Dr1 = Address;
  619. Dr7.Bits.G1 = 0;
  620. Dr7.Bits.RW1 = 0;
  621. Dr7.Bits.LEN1 = 0;
  622. } else if (Register == 2) {
  623. SystemContext.SystemContextIa32->Dr2 = Address;
  624. Dr7.Bits.G2 = 0;
  625. Dr7.Bits.RW2 = 0;
  626. Dr7.Bits.LEN2 = 0;
  627. } else if (Register == 3) {
  628. SystemContext.SystemContextIa32->Dr3 = Address;
  629. Dr7.Bits.G3 = 0;
  630. Dr7.Bits.RW3 = 0;
  631. Dr7.Bits.LEN3 = 0;
  632. } else {
  633. return EFI_INVALID_PARAMETER;
  634. }
  635. // Update DR7 register so appropriate Gn, RWn and LENn bits can be turned off.
  636. SystemContext.SystemContextIa32->Dr7 = Dr7.UintN;
  637. return EFI_SUCCESS;
  638. }
  639. /**
  640. ‘Z1, [addr], [length]’
  641. ‘Z2, [addr], [length]’
  642. ‘Z3, [addr], [length]’
  643. ‘Z4, [addr], [length]’
  644. Insert hardware breakpoint/watchpoint at address addr of size length
  645. @param SystemContext Register content at time of the exception
  646. @param *PacketData Pointer to the Payload data for the packet
  647. **/
  648. VOID
  649. EFIAPI
  650. InsertBreakPoint (
  651. IN EFI_SYSTEM_CONTEXT SystemContext,
  652. IN CHAR8 *PacketData
  653. )
  654. {
  655. UINTN Type;
  656. UINTN Address;
  657. UINTN Length;
  658. UINTN Register;
  659. EFI_STATUS Status;
  660. BREAK_TYPE BreakType = NotSupported;
  661. UINTN ErrorCode;
  662. ErrorCode = ParseBreakpointPacket (PacketData, &Type, &Address, &Length);
  663. if (ErrorCode > 0) {
  664. SendError ((UINT8)ErrorCode);
  665. return;
  666. }
  667. switch (Type) {
  668. case 0: // Software breakpoint
  669. BreakType = SoftwareBreakpoint;
  670. break;
  671. case 1: // Hardware breakpoint
  672. BreakType = InstructionExecution;
  673. break;
  674. case 2: // Write watchpoint
  675. BreakType = DataWrite;
  676. break;
  677. case 3: // Read watchpoint
  678. BreakType = DataRead;
  679. break;
  680. case 4: // Access watchpoint
  681. BreakType = DataReadWrite;
  682. break;
  683. default:
  684. Print ((CHAR16 *)L"Insert breakpoint default: %x\n", Type);
  685. SendError (GDB_EINVALIDBRKPOINTTYPE);
  686. return;
  687. }
  688. // Find next free debug register
  689. Status = FindNextFreeDebugRegister (SystemContext, &Register);
  690. if (EFI_ERROR (Status)) {
  691. Print ((CHAR16 *)L"No space left on device\n");
  692. SendError (GDB_ENOSPACE);
  693. return;
  694. }
  695. // Write Address, length data at particular DR register
  696. Status = EnableDebugRegister (SystemContext, Register, Address, Length, (UINTN)BreakType);
  697. if (EFI_ERROR (Status)) {
  698. if (Status == EFI_UNSUPPORTED) {
  699. Print ((CHAR16 *)L"Not supported\n");
  700. SendNotSupported ();
  701. return;
  702. }
  703. Print ((CHAR16 *)L"Invalid argument\n");
  704. SendError (GDB_EINVALIDARG);
  705. return;
  706. }
  707. SendSuccess ();
  708. }
  709. /**
  710. ‘z1, [addr], [length]’
  711. ‘z2, [addr], [length]’
  712. ‘z3, [addr], [length]’
  713. ‘z4, [addr], [length]’
  714. Remove hardware breakpoint/watchpoint at address addr of size length
  715. @param *PacketData Pointer to the Payload data for the packet
  716. **/
  717. VOID
  718. EFIAPI
  719. RemoveBreakPoint (
  720. IN EFI_SYSTEM_CONTEXT SystemContext,
  721. IN CHAR8 *PacketData
  722. )
  723. {
  724. UINTN Type;
  725. UINTN Address;
  726. UINTN Length;
  727. UINTN Register;
  728. BREAK_TYPE BreakType = NotSupported;
  729. EFI_STATUS Status;
  730. UINTN ErrorCode;
  731. // Parse breakpoint packet data
  732. ErrorCode = ParseBreakpointPacket (PacketData, &Type, &Address, &Length);
  733. if (ErrorCode > 0) {
  734. SendError ((UINT8)ErrorCode);
  735. return;
  736. }
  737. switch (Type) {
  738. case 0: // Software breakpoint
  739. BreakType = SoftwareBreakpoint;
  740. break;
  741. case 1: // Hardware breakpoint
  742. BreakType = InstructionExecution;
  743. break;
  744. case 2: // Write watchpoint
  745. BreakType = DataWrite;
  746. break;
  747. case 3: // Read watchpoint
  748. BreakType = DataRead;
  749. break;
  750. case 4: // Access watchpoint
  751. BreakType = DataReadWrite;
  752. break;
  753. default:
  754. SendError (GDB_EINVALIDBRKPOINTTYPE);
  755. return;
  756. }
  757. // Find matching debug register
  758. Status = FindMatchingDebugRegister (SystemContext, Address, Length, (UINTN)BreakType, &Register);
  759. if (EFI_ERROR (Status)) {
  760. if (Status == EFI_UNSUPPORTED) {
  761. Print ((CHAR16 *)L"Not supported.\n");
  762. SendNotSupported ();
  763. return;
  764. }
  765. Print ((CHAR16 *)L"No matching register found.\n");
  766. SendError (GDB_ENOSPACE);
  767. return;
  768. }
  769. // Remove breakpoint
  770. Status = DisableDebugRegister (SystemContext, Register);
  771. if (EFI_ERROR (Status)) {
  772. Print ((CHAR16 *)L"Invalid argument.\n");
  773. SendError (GDB_EINVALIDARG);
  774. return;
  775. }
  776. SendSuccess ();
  777. }
  778. VOID
  779. InitializeProcessor (
  780. VOID
  781. )
  782. {
  783. }
  784. BOOLEAN
  785. ValidateAddress (
  786. IN VOID *Address
  787. )
  788. {
  789. return TRUE;
  790. }
  791. BOOLEAN
  792. ValidateException (
  793. IN EFI_EXCEPTION_TYPE ExceptionType,
  794. IN OUT EFI_SYSTEM_CONTEXT SystemContext
  795. )
  796. {
  797. return TRUE;
  798. }