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