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