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