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