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