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