]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - EmbeddedPkg/Library/GdbDebugAgent/Ia32/Processor.c
ARM Packages: Corrected non-DOS line endings
[mirror_edk2.git] / EmbeddedPkg / Library / GdbDebugAgent / Ia32 / Processor.c
... / ...
CommitLineData
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
5 \r
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 <GdbDebugAgent.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
23 { EXCEPT_IA32_DIVIDE_ERROR, GDB_SIGFPE }, \r
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
65VOID \r
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
83VOID \r
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
99 \r
100 @retval UINTN, the number of entries in the gExceptionType[] array. \r
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 Check to see if the ISA is supported. \r
113 ISA = Instruction Set Architecture\r
114 \r
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
131 @param SystemContext Register content at time of the exception \r
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
138 IN UINTN RegNumber \r
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
163 \r
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
174/** ‘p n’ \r
175 Reads the n-th register's value into an output buffer and sends it as a packet \r
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
190 \r
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
206/** ‘g’ \r
207 Reads the general registers into an output buffer and sends it as a packet \r
208\r
209 @param SystemContext Register content at time of the exception\r
210 **/\r
211VOID\r
212EFIAPI\r
213ReadGeneralRegisters ( \r
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
222 for(i = 0 ; i < sizeof (gRegisterOffsets)/sizeof (UINTN) ; i++) { // there are only 16 registers to read \r
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
249 \r
250 NewValue = 0;\r
251 RegSize = 0;\r
252 while (RegSize < REG_SIZE) {\r
253 TempValue = HexCharToInt(*InBufPtr++);\r
254 \r
255 if (TempValue < 0) {\r
256 SendError (GDB_EBADMEMDATA); \r
257 return NULL;\r
258 }\r
259\r
260 NewValue += (TempValue << (RegSize+4));\r
261 TempValue = HexCharToInt(*InBufPtr++);\r
262 \r
263 if (TempValue < 0) {\r
264 SendError (GDB_EBADMEMDATA); \r
265 return NULL;\r
266 }\r
267 \r
268 NewValue += (TempValue << RegSize); \r
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
293 \r
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
299 } \r
300 *RegNumBufPtr = '\0';\r
301 RegNumber = AsciiStrHexToUintn (RegNumBuffer); \r
302\r
303 // check if this is a valid Register Number\r
304 if ((RegNumber < 0) || (RegNumber >= sizeof (gRegisterOffsets)/sizeof (UINTN))) {\r
305 SendError (GDB_EINVALIDREGNUM); \r
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
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
332 if (AsciiStrLen(InBuffer) != 129) { // 16 regs, 8 hex chars each, and the end '\0' (escape seq)\r
333 //Bad message. Message is not the right length \r
334 SendError (GDB_EBADBUFSIZE); \r
335 return;\r
336 }\r
337\r
338 InBufPtr = &InBuffer[1];\r
339 \r
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
349/** ‘c [addr ]’ \r
350 Continue. addr is Address to resume. If addr is omitted, resume at current \r
351 Address.\r
352 \r
353 @param SystemContext Register content at time of the exception \r
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
364 } \r
365}\r
366\r
367\r
368/** ‘s [addr ]’\r
369 Single step. addr is the Address at which to resume. If addr is omitted, resume \r
370 at same Address.\r
371 \r
372 @param SystemContext Register content at time of the exception \r
373 **/\r
374VOID\r
375EFIAPI\r
376SingleStep (\r
377 IN EFI_SYSTEM_CONTEXT SystemContext,\r
378 IN CHAR8 *PacketData\r
379 )\r
380{\r
381 SendNotSupported();\r
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
424 @retval {1-4} Currently detected breakpoint value \r
425 @retval 0 No breakpoint detected.\r
426 \r
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
447 BreakpointNumber = 0; //No breakpoint detected \r
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
457 \r
458 @param SystemContext Register content at time of the exception\r
459 @param BreakpointNumber Breakpoint number\r
460 \r
461 @retval BREAK_TYPE Breakpoint type value read from register DR7 RWn field\r
462 For unknown value, it returns NotSupported.\r
463 \r
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
477 Type = (BREAK_TYPE) Dr7.Bits.RW0; \r
478 } else if (BreakpointNumber == 2) {\r
479 Type = (BREAK_TYPE) Dr7.Bits.RW1; \r
480 } else if (BreakpointNumber == 3) {\r
481 Type = (BREAK_TYPE) Dr7.Bits.RW2; \r
482 } else if (BreakpointNumber == 4) {\r
483 Type = (BREAK_TYPE) Dr7.Bits.RW3; \r
484 }\r
485\r
486 return Type;\r
487}\r
488\r
489\r
490/** \r
491 Parses Length and returns the length which DR7 LENn field accepts.\r
492 For example: If we receive 1-Byte length then we should return 0. \r
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
505 if (Length == 1) { //1-Byte length \r
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
518 Finds the next free debug register. If all the registers are occupied then \r
519 EFI_OUT_OF_RESOURCES is returned. \r
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
556 \r
557 @param SystemContext Register content at time of the exception\r
558 @param Register Register value (0 - 3) \r
559 @param Address Breakpoint address value\r
560 @param Type Breakpoint type (Instruction, Data write, Data read \r
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
580 //For Instruction execution, length should be 0 \r
581 //(Ref. Intel reference manual 18.2.4)\r
582 if ((Type == 0) && (Length != 0)) {\r
583 return EFI_INVALID_PARAMETER;\r
584 }\r
585 \r
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
588 if ((Type == (BREAK_TYPE)DataRead) || \r
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
620 //Update Dr7 with appropriate Gn, RWn and LENn bits \r
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
636 @param Type Breakpoint type (Instruction, Data write, \r
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
656 if ((Type == (BREAK_TYPE)DataRead) || \r
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
666 if ((Dr7.Bits.G0 == 1) && \r
667 (Dr7.Bits.LEN0 == Length) &&\r
668 (Dr7.Bits.RW0 == Type) && \r
669 (Address == SystemContext.SystemContextIa32->Dr0)) {\r
670 *Register = 0;\r
671 } else if ((Dr7.Bits.G1 == 1) && \r
672 (Dr7.Bits.LEN1 == Length) &&\r
673 (Dr7.Bits.RW1 == Type) && \r
674 (Address == SystemContext.SystemContextIa32->Dr1)) {\r
675 *Register = 1;\r
676 } else if ((Dr7.Bits.G2 == 1) && \r
677 (Dr7.Bits.LEN2 == Length) &&\r
678 (Dr7.Bits.RW2 == Type) && \r
679 (Address == SystemContext.SystemContextIa32->Dr2)) {\r
680 *Register = 2;\r
681 } else if ((Dr7.Bits.G3 == 1) && \r
682 (Dr7.Bits.LEN3 == Length) &&\r
683 (Dr7.Bits.RW3 == Type) && \r
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
707 IN UINTN Register \r
708 )\r
709{\r
710 IA32_DR7 Dr7;\r
711 UINTN Address = 0;\r
712 \r
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
866 \r
867 case 0: //Software breakpoint\r
868 BreakType = SoftwareBreakpoint;\r
869 break;\r
870 \r
871 case 1: //Hardware breakpoint\r
872 BreakType = InstructionExecution;\r
873 break;\r
874 \r
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
915/**\r
916 Initialize debug agent.\r
917\r
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
924\r
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
935\r
936**/\r
937VOID\r
938EFIAPI\r
939InitializeDebugAgent (\r
940 IN UINT32 InitFlag,\r
941 IN VOID *Context, OPTIONAL\r
942 IN DEBUG_AGENT_CONTINUE Function OPTIONAL\r
943 )\r
944{\r
945 // BugBug: Add the code to build an GDT/IDT\r
946\r
947 if (Function != NULL) {\r
948 Function (Context);\r
949 }\r
950}\r
951\r