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