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