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