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