Update the copyright notice format
[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 enviroment. It may enable interrupts.
919
920 @param[in] InitFlag Init flag is used to decide initialize process.
921 @param[in] Context Context needed according to InitFlag, it was optional.
922
923 **/
924 VOID
925 EFIAPI
926 InitializeDebugAgent (
927 IN UINT32 InitFlag,
928 IN VOID *Context OPTIONAL
929 )
930 {
931 // BugBug: Add the code to build an GDT/IDT
932 }
933