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