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