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