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