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