]> git.proxmox.com Git - mirror_edk2.git/blob - EmbeddedPkg/GdbStub/Arm/Processor.c
7626f5df52215e9621c41d621015162c80e11162
[mirror_edk2.git] / EmbeddedPkg / GdbStub / Arm / Processor.c
1 /** @file
2 Processor specific parts of the GDB stub
3
4 Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
5
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include <GdbStubInternal.h>
17 #include <Library/CacheMaintenanceLib.h>
18 #include <Library/PrintLib.h>
19
20 //
21 // Array of exception types that need to be hooked by the debugger
22 // (efi, gdb) //efi number
23 //
24 EFI_EXCEPTION_TYPE_ENTRY gExceptionType[] = {
25 { EXCEPT_ARM_SOFTWARE_INTERRUPT, GDB_SIGTRAP }
26 // { EXCEPT_ARM_UNDEFINED_INSTRUCTION, GDB_SIGTRAP },
27 // { EXCEPT_ARM_PREFETCH_ABORT, GDB_SIGTRAP },
28 // { EXCEPT_ARM_DATA_ABORT, GDB_SIGEMT },
29 // { EXCEPT_ARM_RESERVED, GDB_SIGILL }
30 };
31
32 // Shut up some annoying RVCT warnings
33 #ifdef __CC_ARM
34 #pragma diag_suppress 1296
35 #endif
36
37 UINTN gRegisterOffsets[] = {
38 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R0),
39 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R1),
40 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R2),
41 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R3),
42 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R4),
43 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R5),
44 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R6),
45 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R7),
46 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R8),
47 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R9),
48 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R10),
49 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R11),
50 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R12),
51 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, SP),
52 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, LR),
53 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, PC),
54 0x00000F01, // f0
55 0x00000F02,
56 0x00000F03,
57 0x00000F11, // f1
58 0x00000F12,
59 0x00000F13,
60 0x00000F21, // f2
61 0x00000F22,
62 0x00000F23,
63 0x00000F31, // f3
64 0x00000F32,
65 0x00000F33,
66 0x00000F41, // f4
67 0x00000F42,
68 0x00000F43,
69 0x00000F51, // f5
70 0x00000F52,
71 0x00000F53,
72 0x00000F61, // f6
73 0x00000F62,
74 0x00000F63,
75 0x00000F71, // f7
76 0x00000F72,
77 0x00000F73,
78 0x00000FFF, // fps
79 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, CPSR)
80 };
81
82 // restore warnings for RVCT
83 #ifdef __CC_ARM
84 #pragma diag_default 1296
85 #endif
86
87 /**
88 Return the number of entries in the gExceptionType[]
89
90 @retval UINTN, the number of entries in the gExceptionType[] array.
91 **/
92 UINTN
93 MaxEfiException (
94 VOID
95 )
96 {
97 return sizeof (gExceptionType)/sizeof (EFI_EXCEPTION_TYPE_ENTRY);
98 }
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 /**
116 Check to see if the ISA is supported.
117 ISA = Instruction Set Architecture
118
119 @retval TRUE if Isa is supported
120
121 **/
122 BOOLEAN
123 CheckIsa (
124 IN EFI_INSTRUCTION_SET_ARCHITECTURE Isa
125 )
126 {
127 if (Isa == IsaArm) {
128 return TRUE;
129 } else {
130 return FALSE;
131 }
132 }
133
134
135 /**
136 This takes in the register number and the System Context, and returns a pointer to the RegNumber-th register in gdb ordering
137 It is, by default, set to find the register pointer of the ARM member
138 @param SystemContext Register content at time of the exception
139 @param RegNumber The register to which we want to find a pointer
140 @retval the pointer to the RegNumber-th pointer
141 **/
142 UINTN *
143 FindPointerToRegister(
144 IN EFI_SYSTEM_CONTEXT SystemContext,
145 IN UINTN RegNumber
146 )
147 {
148 UINT8 *TempPtr;
149 ASSERT(gRegisterOffsets[RegNumber] < 0xF00);
150 TempPtr = ((UINT8 *)SystemContext.SystemContextArm) + gRegisterOffsets[RegNumber];
151 return (UINT32 *)TempPtr;
152 }
153
154
155 /**
156 Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr
157 @param SystemContext Register content at time of the exception
158 @param RegNumber the number of the register that we want to read
159 @param OutBufPtr pointer to the output buffer's end. the new data will be added from this point on.
160 @retval the pointer to the next character of the output buffer that is available to be written on.
161 **/
162 CHAR8 *
163 BasicReadRegister (
164 IN EFI_SYSTEM_CONTEXT SystemContext,
165 IN UINTN RegNumber,
166 IN CHAR8 *OutBufPtr
167 )
168 {
169 UINTN RegSize;
170 CHAR8 Char;
171
172 if (gRegisterOffsets[RegNumber] > 0xF00) {
173 AsciiSPrint(OutBufPtr, 9, "00000000");
174 OutBufPtr += 8;
175 return OutBufPtr;
176 }
177
178 RegSize = 0;
179 while (RegSize < 32) {
180 Char = mHexToStr[(UINT8)((*FindPointerToRegister(SystemContext, RegNumber) >> (RegSize+4)) & 0xf)];
181 if ((Char >= 'A') && (Char <= 'F')) {
182 Char = Char - 'A' + 'a';
183 }
184 *OutBufPtr++ = Char;
185
186 Char = mHexToStr[(UINT8)((*FindPointerToRegister(SystemContext, RegNumber) >> RegSize) & 0xf)];
187 if ((Char >= 'A') && (Char <= 'F')) {
188 Char = Char - 'A' + 'a';
189 }
190 *OutBufPtr++ = Char;
191
192 RegSize = RegSize + 8;
193 }
194 return OutBufPtr;
195 }
196
197
198 /** ‘p n’
199 Reads the n-th register's value into an output buffer and sends it as a packet
200 @param SystemContext Register content at time of the exception
201 @param InBuffer Pointer to the input buffer received from gdb server
202 **/
203 VOID
204 ReadNthRegister (
205 IN EFI_SYSTEM_CONTEXT SystemContext,
206 IN CHAR8 *InBuffer
207 )
208 {
209 UINTN RegNumber;
210 CHAR8 OutBuffer[9]; // 1 reg=8 hex chars, and the end '\0' (escape seq)
211 CHAR8 *OutBufPtr; // pointer to the output buffer
212
213 RegNumber = AsciiStrHexToUintn (&InBuffer[1]);
214
215 if (RegNumber >= MaxRegisterCount()) {
216 SendError (GDB_EINVALIDREGNUM);
217 return;
218 }
219
220 OutBufPtr = OutBuffer;
221 OutBufPtr = BasicReadRegister (SystemContext, RegNumber, OutBufPtr);
222
223 *OutBufPtr = '\0'; // the end of the buffer
224 SendPacket(OutBuffer);
225 }
226
227
228 /** ‘g’
229 Reads the general registers into an output buffer and sends it as a packet
230 @param SystemContext Register content at time of the exception
231 **/
232 VOID
233 EFIAPI
234 ReadGeneralRegisters (
235 IN EFI_SYSTEM_CONTEXT SystemContext
236 )
237 {
238 UINTN Index;
239 CHAR8 *OutBuffer;
240 CHAR8 *OutBufPtr;
241 UINTN RegisterCount = MaxRegisterCount();
242
243 // It is not safe to allocate pool here....
244 OutBuffer = AllocatePool((RegisterCount * 8) + 1); // 8 bytes per register in string format plus a null to terminate
245 OutBufPtr = OutBuffer;
246 for (Index = 0; Index < RegisterCount; Index++) {
247 OutBufPtr = BasicReadRegister (SystemContext, Index, OutBufPtr);
248 }
249
250 *OutBufPtr = '\0';
251 SendPacket(OutBuffer);
252 FreePool(OutBuffer);
253 }
254
255
256 /**
257 Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr
258 @param SystemContext Register content at time of the exception
259 @param RegNumber the number of the register that we want to write
260 @param InBufPtr pointer to the output buffer. the new data will be extracted from the input buffer from this point on.
261 @retval the pointer to the next character of the input buffer that can be used
262 **/
263 CHAR8
264 *BasicWriteRegister (
265 IN EFI_SYSTEM_CONTEXT SystemContext,
266 IN UINTN RegNumber,
267 IN CHAR8 *InBufPtr
268 )
269 {
270 UINTN RegSize;
271 UINTN TempValue; // the value transferred from a hex char
272 UINT32 NewValue; // the new value of the RegNumber-th Register
273
274 if (gRegisterOffsets[RegNumber] > 0xF00) {
275 return InBufPtr + 8;
276 }
277
278 NewValue = 0;
279 RegSize = 0;
280 while (RegSize < 32) {
281 TempValue = HexCharToInt(*InBufPtr++);
282
283 if ((INTN)TempValue < 0) {
284 SendError (GDB_EBADMEMDATA);
285 return NULL;
286 }
287
288 NewValue += (TempValue << (RegSize+4));
289 TempValue = HexCharToInt(*InBufPtr++);
290
291 if ((INTN)TempValue < 0) {
292 SendError (GDB_EBADMEMDATA);
293 return NULL;
294 }
295
296 NewValue += (TempValue << RegSize);
297 RegSize = RegSize + 8;
298 }
299 *(FindPointerToRegister(SystemContext, RegNumber)) = NewValue;
300 return InBufPtr;
301 }
302
303
304 /** ‘P n...=r...’
305 Writes the new value of n-th register received into the input buffer to the n-th register
306 @param SystemContext Register content at time of the exception
307 @param InBuffer Ponter to the input buffer received from gdb server
308 **/
309 VOID
310 WriteNthRegister (
311 IN EFI_SYSTEM_CONTEXT SystemContext,
312 IN CHAR8 *InBuffer
313 )
314 {
315 UINTN RegNumber;
316 CHAR8 RegNumBuffer[MAX_REG_NUM_BUF_SIZE]; // put the 'n..' part of the message into this array
317 CHAR8 *RegNumBufPtr;
318 CHAR8 *InBufPtr; // pointer to the input buffer
319
320 // find the register number to write
321 InBufPtr = &InBuffer[1];
322 RegNumBufPtr = RegNumBuffer;
323 while (*InBufPtr != '=') {
324 *RegNumBufPtr++ = *InBufPtr++;
325 }
326 *RegNumBufPtr = '\0';
327 RegNumber = AsciiStrHexToUintn (RegNumBuffer);
328
329 // check if this is a valid Register Number
330 if (RegNumber >= MaxRegisterCount()) {
331 SendError (GDB_EINVALIDREGNUM);
332 return;
333 }
334 InBufPtr++; // skips the '=' character
335 BasicWriteRegister (SystemContext, RegNumber, InBufPtr);
336 SendSuccess();
337 }
338
339
340 /** ‘G XX...’
341 Writes the new values received into the input buffer to the general registers
342 @param SystemContext Register content at time of the exception
343 @param InBuffer Pointer to the input buffer received from gdb server
344 **/
345
346 VOID
347 EFIAPI
348 WriteGeneralRegisters (
349 IN EFI_SYSTEM_CONTEXT SystemContext,
350 IN CHAR8 *InBuffer
351 )
352 {
353 UINTN i;
354 CHAR8 *InBufPtr; /// pointer to the input buffer
355 UINTN MinLength;
356 UINTN RegisterCount = MaxRegisterCount();
357
358 MinLength = (RegisterCount * 8) + 1; // 'G' plus the registers in ASCII format
359
360 if (AsciiStrLen(InBuffer) < MinLength) {
361 //Bad message. Message is not the right length
362 SendError (GDB_EBADBUFSIZE);
363 return;
364 }
365
366 InBufPtr = &InBuffer[1];
367
368 // Read the new values for the registers from the input buffer to an array, NewValueArray.
369 // The values in the array are in the gdb ordering
370 for(i = 0; i < RegisterCount; i++) {
371 InBufPtr = BasicWriteRegister (SystemContext, i, InBufPtr);
372 }
373
374 SendSuccess ();
375 }
376
377 // What about Thumb?
378 // Use SWI 0xdbdbdb as the debug instruction
379 #define GDB_ARM_BKPT 0xefdbdbdb
380
381 BOOLEAN mSingleStepActive = FALSE;
382 UINT32 mSingleStepPC;
383 UINT32 mSingleStepData;
384 UINTN mSingleStepDataSize;
385
386 typedef struct {
387 LIST_ENTRY Link;
388 UINT64 Signature;
389 UINT32 Address;
390 UINT32 Instruction;
391 } ARM_SOFTWARE_BREAKPOINT;
392
393 #define ARM_SOFTWARE_BREAKPOINT_SIGNATURE SIGNATURE_64('A', 'R', 'M', 'B', 'R', 'K', 'P', 'T')
394 #define ARM_SOFTWARE_BREAKPOINT_FROM_LINK(a) CR(a, ARM_SOFTWARE_BREAKPOINT, Link, ARM_SOFTWARE_BREAKPOINT_SIGNATURE)
395
396 LIST_ENTRY BreakpointList;
397
398 /**
399 Insert Single Step in the SystemContext
400
401 @param SystemContext Register content at time of the exception
402 **/
403 VOID
404 AddSingleStep (
405 IN EFI_SYSTEM_CONTEXT SystemContext
406 )
407 {
408 if (mSingleStepActive) {
409 // Currently don't support nesting
410 return;
411 }
412 mSingleStepActive = TRUE;
413
414 mSingleStepPC = SystemContext.SystemContextArm->PC;
415
416 mSingleStepDataSize = sizeof (UINT32);
417 mSingleStepData = (*(UINT32 *)mSingleStepPC);
418 *(UINT32 *)mSingleStepPC = GDB_ARM_BKPT;
419 if (*(UINT32 *)mSingleStepPC != GDB_ARM_BKPT) {
420 // For some reason our breakpoint did not take
421 mSingleStepActive = FALSE;
422 }
423
424 InvalidateInstructionCacheRange((VOID *)mSingleStepPC, mSingleStepDataSize);
425 //DEBUG((EFI_D_ERROR, "AddSingleStep at 0x%08x (was: 0x%08x is:0x%08x)\n", SystemContext.SystemContextArm->PC, mSingleStepData, *(UINT32 *)mSingleStepPC));
426 }
427
428
429 /**
430 Remove Single Step in the SystemContext
431
432 @param SystemContext Register content at time of the exception
433 **/
434 VOID
435 RemoveSingleStep (
436 IN EFI_SYSTEM_CONTEXT SystemContext
437 )
438 {
439 if (!mSingleStepActive) {
440 return;
441 }
442
443 if (mSingleStepDataSize == sizeof (UINT16)) {
444 *(UINT16 *)mSingleStepPC = (UINT16)mSingleStepData;
445 } else {
446 //DEBUG((EFI_D_ERROR, "RemoveSingleStep at 0x%08x (was: 0x%08x is:0x%08x)\n", SystemContext.SystemContextArm->PC, *(UINT32 *)mSingleStepPC, mSingleStepData));
447 *(UINT32 *)mSingleStepPC = mSingleStepData;
448 }
449 InvalidateInstructionCacheRange((VOID *)mSingleStepPC, mSingleStepDataSize);
450 mSingleStepActive = FALSE;
451 }
452
453
454
455 /** ‘c [addr ]’
456 Continue. addr is Address to resume. If addr is omitted, resume at current
457 Address.
458
459 @param SystemContext Register content at time of the exception
460 **/
461 VOID
462 EFIAPI
463 ContinueAtAddress (
464 IN EFI_SYSTEM_CONTEXT SystemContext,
465 IN CHAR8 *PacketData
466 )
467 {
468 if (PacketData[1] != '\0') {
469 SystemContext.SystemContextArm->PC = AsciiStrHexToUintn(&PacketData[1]);
470 }
471 }
472
473
474 /** ‘s [addr ]’
475 Single step. addr is the Address at which to resume. If addr is omitted, resume
476 at same Address.
477
478 @param SystemContext Register content at time of the exception
479 **/
480 VOID
481 EFIAPI
482 SingleStep (
483 IN EFI_SYSTEM_CONTEXT SystemContext,
484 IN CHAR8 *PacketData
485 )
486 {
487 SendNotSupported();
488 }
489
490 UINTN
491 GetBreakpointDataAddress (
492 IN EFI_SYSTEM_CONTEXT SystemContext,
493 IN UINTN BreakpointNumber
494 )
495 {
496 return 0;
497 }
498
499 UINTN
500 GetBreakpointDetected (
501 IN EFI_SYSTEM_CONTEXT SystemContext
502 )
503 {
504 return 0;
505 }
506
507 BREAK_TYPE
508 GetBreakpointType (
509 IN EFI_SYSTEM_CONTEXT SystemContext,
510 IN UINTN BreakpointNumber
511 )
512 {
513 return NotSupported;
514 }
515
516 ARM_SOFTWARE_BREAKPOINT *
517 SearchBreakpointList (
518 IN UINT32 Address
519 )
520 {
521 LIST_ENTRY *Current;
522 ARM_SOFTWARE_BREAKPOINT *Breakpoint;
523
524 Current = GetFirstNode(&BreakpointList);
525 while (!IsNull(&BreakpointList, Current)) {
526 Breakpoint = ARM_SOFTWARE_BREAKPOINT_FROM_LINK(Current);
527
528 if (Address == Breakpoint->Address) {
529 return Breakpoint;
530 }
531
532 Current = GetNextNode(&BreakpointList, Current);
533 }
534
535 return NULL;
536 }
537
538 VOID
539 SetBreakpoint (
540 IN UINT32 Address
541 )
542 {
543 ARM_SOFTWARE_BREAKPOINT *Breakpoint;
544
545 Breakpoint = SearchBreakpointList(Address);
546
547 if (Breakpoint != NULL) {
548 return;
549 }
550
551 // create and fill breakpoint structure
552 Breakpoint = AllocatePool(sizeof(ARM_SOFTWARE_BREAKPOINT));
553
554 Breakpoint->Signature = ARM_SOFTWARE_BREAKPOINT_SIGNATURE;
555 Breakpoint->Address = Address;
556 Breakpoint->Instruction = *(UINT32 *)Address;
557
558 // Add it to the list
559 InsertTailList(&BreakpointList, &Breakpoint->Link);
560
561 // Insert the software breakpoint
562 *(UINT32 *)Address = GDB_ARM_BKPT;
563 InvalidateInstructionCacheRange((VOID *)Address, 4);
564
565 //DEBUG((EFI_D_ERROR, "SetBreakpoint at 0x%08x (was: 0x%08x is:0x%08x)\n", Address, Breakpoint->Instruction, *(UINT32 *)Address));
566 }
567
568 VOID
569 ClearBreakpoint (
570 IN UINT32 Address
571 )
572 {
573 ARM_SOFTWARE_BREAKPOINT *Breakpoint;
574
575 Breakpoint = SearchBreakpointList(Address);
576
577 if (Breakpoint == NULL) {
578 return;
579 }
580
581 // Add it to the list
582 RemoveEntryList(&Breakpoint->Link);
583
584 // Restore the original instruction
585 *(UINT32 *)Address = Breakpoint->Instruction;
586 InvalidateInstructionCacheRange((VOID *)Address, 4);
587
588 //DEBUG((EFI_D_ERROR, "ClearBreakpoint at 0x%08x (was: 0x%08x is:0x%08x)\n", Address, GDB_ARM_BKPT, *(UINT32 *)Address));
589
590 FreePool(Breakpoint);
591 }
592
593 VOID
594 EFIAPI
595 InsertBreakPoint (
596 IN EFI_SYSTEM_CONTEXT SystemContext,
597 IN CHAR8 *PacketData
598 )
599 {
600 UINTN Type;
601 UINTN Address;
602 UINTN Length;
603 UINTN ErrorCode;
604
605 ErrorCode = ParseBreakpointPacket(PacketData, &Type, &Address, &Length);
606 if (ErrorCode > 0) {
607 SendError ((UINT8)ErrorCode);
608 return;
609 }
610
611 switch (Type) {
612 case 0: //Software breakpoint
613 break;
614
615 default :
616 DEBUG((EFI_D_ERROR, "Insert breakpoint default: %x\n", Type));
617 SendError (GDB_EINVALIDBRKPOINTTYPE);
618 return;
619 }
620
621 SetBreakpoint(Address);
622
623 SendSuccess ();
624 }
625
626 VOID
627 EFIAPI
628 RemoveBreakPoint (
629 IN EFI_SYSTEM_CONTEXT SystemContext,
630 IN CHAR8 *PacketData
631 )
632 {
633 UINTN Type;
634 UINTN Address;
635 UINTN Length;
636 UINTN ErrorCode;
637
638 //Parse breakpoint packet data
639 ErrorCode = ParseBreakpointPacket (PacketData, &Type, &Address, &Length);
640 if (ErrorCode > 0) {
641 SendError ((UINT8)ErrorCode);
642 return;
643 }
644
645 switch (Type) {
646 case 0: //Software breakpoint
647 break;
648
649 default:
650 SendError (GDB_EINVALIDBRKPOINTTYPE);
651 return;
652 }
653
654 ClearBreakpoint(Address);
655
656 SendSuccess ();
657 }
658
659 VOID
660 InitializeProcessor (
661 VOID
662 )
663 {
664 // Initialize breakpoint list
665 InitializeListHead(&BreakpointList);
666 }
667
668 BOOLEAN
669 ValidateAddress (
670 IN VOID *Address
671 )
672 {
673 if ((UINT32)Address < 0x80000000) {
674 return FALSE;
675 } else {
676 return TRUE;
677 }
678 }
679
680 BOOLEAN
681 ValidateException (
682 IN EFI_EXCEPTION_TYPE ExceptionType,
683 IN OUT EFI_SYSTEM_CONTEXT SystemContext
684 )
685 {
686 UINT32 ExceptionAddress;
687 UINT32 Instruction;
688
689 // Is it a debugger SWI?
690 ExceptionAddress = SystemContext.SystemContextArm->PC -= 4;
691 Instruction = *(UINT32 *)ExceptionAddress;
692 if (Instruction != GDB_ARM_BKPT) {
693 return FALSE;
694 }
695
696 // Special for SWI-based exception handling. SWI sets up the context
697 // to return to the instruction following the SWI instruction - NOT what we want
698 // for a debugger!
699 SystemContext.SystemContextArm->PC = ExceptionAddress;
700
701 return TRUE;
702 }
703