]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/Library/GdbDebugAgent/Arm/Processor.c
Clean up using FIQ as ctrl-c checker so you can break in from the debugger.
[mirror_edk2.git] / EmbeddedPkg / Library / GdbDebugAgent / Arm / Processor.c
CommitLineData
969eba7b 1/** @file\r
2 Processor specific parts of the GDB stub\r
3\r
4 Copyright (c) 2008-2010, 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\r
16\r
17#include <GdbDebugAgent.h>\r
18#include <Library/CacheMaintenanceLib.h>\r
19#include <Library/PrintLib.h>\r
20#include <Library/ArmLib.h>\r
21\r
22//\r
23// Externs from the exception handler assembly file\r
24//\r
25VOID\r
26ExceptionHandlersStart (\r
27 VOID\r
28 );\r
29\r
30VOID\r
31ExceptionHandlersEnd (\r
32 VOID\r
33 );\r
34\r
35VOID\r
36CommonExceptionEntry (\r
37 VOID\r
38 );\r
39\r
40VOID\r
41AsmCommonExceptionEntry (\r
42 VOID\r
43 );\r
44\r
45\r
46//\r
47// Array of exception types that need to be hooked by the debugger\r
48// (efi, gdb) //efi number\r
49//\r
50EFI_EXCEPTION_TYPE_ENTRY gExceptionType[] = {\r
51 { EXCEPT_ARM_SOFTWARE_INTERRUPT, GDB_SIGTRAP },\r
52 { EXCEPT_ARM_UNDEFINED_INSTRUCTION, GDB_SIGTRAP }, \r
53 { EXCEPT_ARM_PREFETCH_ABORT, GDB_SIGTRAP }, \r
54 { EXCEPT_ARM_DATA_ABORT, GDB_SIGTRAP }, // GDB_SIGEMT\r
55 { EXCEPT_ARM_RESERVED, GDB_SIGTRAP }, // GDB_SIGILL\r
56 { EXCEPT_ARM_FIQ, GDB_SIGINT } // Used for ctrl-c\r
57};\r
58\r
59// Shut up some annoying RVCT warnings\r
60#ifdef __CC_ARM\r
61#pragma diag_suppress 1296\r
62#endif\r
63\r
64UINTN gRegisterOffsets[] = {\r
65 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R0),\r
66 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R1),\r
67 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R2),\r
68 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R3),\r
69 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R4),\r
70 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R5),\r
71 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R6),\r
72 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R7),\r
73 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R8),\r
74 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R9),\r
75 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R10),\r
76 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R11),\r
77 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R12),\r
78 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, SP),\r
79 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, LR),\r
80 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, PC),\r
81 0x00000F01, // f0\r
82 0x00000F02,\r
83 0x00000F03,\r
84 0x00000F11, // f1\r
85 0x00000F12,\r
86 0x00000F13,\r
87 0x00000F21, // f2\r
88 0x00000F22,\r
89 0x00000F23,\r
90 0x00000F31, // f3\r
91 0x00000F32,\r
92 0x00000F33,\r
93 0x00000F41, // f4\r
94 0x00000F42,\r
95 0x00000F43,\r
96 0x00000F51, // f5\r
97 0x00000F52,\r
98 0x00000F53,\r
99 0x00000F61, // f6\r
100 0x00000F62,\r
101 0x00000F63,\r
102 0x00000F71, // f7\r
103 0x00000F72,\r
104 0x00000F73,\r
105 0x00000FFF, // fps\r
106 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, CPSR)\r
107};\r
108\r
109// restore warnings for RVCT\r
110#ifdef __CC_ARM\r
111#pragma diag_default 1296\r
112#endif\r
113\r
114\r
115/**\r
116 Return the number of entries in the gExceptionType[]\r
117 \r
118 @retval UINTN, the number of entries in the gExceptionType[] array. \r
119 **/\r
120UINTN\r
121MaxEfiException (\r
122 VOID\r
123 )\r
124{\r
125 return sizeof (gExceptionType)/sizeof (EFI_EXCEPTION_TYPE_ENTRY);\r
126}\r
127\r
128\r
129\r
130\r
131/**\r
132 Check to see if the ISA is supported. \r
133 ISA = Instruction Set Architecture\r
134\r
135 @retval TRUE if Isa is supported \r
136\r
137**/\r
138BOOLEAN\r
139CheckIsa (\r
140 IN EFI_INSTRUCTION_SET_ARCHITECTURE Isa\r
141 )\r
142{\r
143 if (Isa == IsaArm) {\r
144 return TRUE;\r
145 } else {\r
146 return FALSE;\r
147 }\r
148}\r
149\r
150\r
151/**\r
152 This takes in the register number and the System Context, and returns a pointer to the RegNumber-th register in gdb ordering\r
153 It is, by default, set to find the register pointer of the ARM member\r
154 @param SystemContext Register content at time of the exception \r
155 @param RegNumber The register to which we want to find a pointer\r
156 @retval the pointer to the RegNumber-th pointer\r
157 **/ \r
158UINTN *\r
159FindPointerToRegister(\r
160 IN EFI_SYSTEM_CONTEXT SystemContext,\r
161 IN UINTN RegNumber \r
162 )\r
163{\r
164 UINT8 *TempPtr;\r
165 ASSERT(gRegisterOffsets[RegNumber] < 0xF00);\r
166 TempPtr = ((UINT8 *)SystemContext.SystemContextArm) + gRegisterOffsets[RegNumber];\r
167 return (UINT32 *)TempPtr;\r
168}\r
169\r
170\r
171/**\r
172 Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr\r
173 @param SystemContext Register content at time of the exception\r
174 @param RegNumber the number of the register that we want to read\r
175 @param OutBufPtr pointer to the output buffer's end. the new data will be added from this point on.\r
176 @retval the pointer to the next character of the output buffer that is available to be written on.\r
177 **/\r
178CHAR8 *\r
179BasicReadRegister (\r
180 IN EFI_SYSTEM_CONTEXT SystemContext,\r
181 IN UINTN RegNumber,\r
182 IN CHAR8 *OutBufPtr\r
183 )\r
184{\r
185 UINTN RegSize;\r
186 CHAR8 Char;\r
187 \r
188 if (gRegisterOffsets[RegNumber] > 0xF00) {\r
189 AsciiSPrint(OutBufPtr, 9, "00000000");\r
190 OutBufPtr += 8;\r
191 return OutBufPtr;\r
192 }\r
193\r
194 RegSize = 0;\r
195 while (RegSize < 32) {\r
196 Char = mHexToStr[(UINT8)((*FindPointerToRegister(SystemContext, RegNumber) >> (RegSize+4)) & 0xf)];\r
197 if ((Char >= 'A') && (Char <= 'F')) {\r
198 Char = Char - 'A' + 'a';\r
199 }\r
200 *OutBufPtr++ = Char;\r
201 \r
202 Char = mHexToStr[(UINT8)((*FindPointerToRegister(SystemContext, RegNumber) >> RegSize) & 0xf)];\r
203 if ((Char >= 'A') && (Char <= 'F')) {\r
204 Char = Char - 'A' + 'a';\r
205 }\r
206 *OutBufPtr++ = Char;\r
207 \r
208 RegSize = RegSize + 8;\r
209 }\r
210 return OutBufPtr;\r
211}\r
212\r
213\r
214/** ‘p n’ \r
215 Reads the n-th register's value into an output buffer and sends it as a packet \r
216 @param SystemContext Register content at time of the exception\r
217 @param InBuffer Pointer to the input buffer received from gdb server\r
218 **/\r
219VOID\r
220ReadNthRegister (\r
221 IN EFI_SYSTEM_CONTEXT SystemContext,\r
222 IN CHAR8 *InBuffer\r
223 )\r
224{\r
225 UINTN RegNumber;\r
226 CHAR8 OutBuffer[9]; // 1 reg=8 hex chars, and the end '\0' (escape seq)\r
227 CHAR8 *OutBufPtr; // pointer to the output buffer\r
228 \r
229 RegNumber = AsciiStrHexToUintn (&InBuffer[1]);\r
230 \r
231 if (RegNumber >= (sizeof (gRegisterOffsets)/sizeof (UINTN))) {\r
232 SendError (GDB_EINVALIDREGNUM); \r
233 return;\r
234 }\r
235 \r
236 OutBufPtr = OutBuffer;\r
237 OutBufPtr = BasicReadRegister (SystemContext, RegNumber, OutBufPtr);\r
238 \r
239 *OutBufPtr = '\0'; // the end of the buffer\r
240 SendPacket(OutBuffer);\r
241}\r
242\r
243\r
244/** ‘g’ \r
245 Reads the general registers into an output buffer and sends it as a packet \r
246 @param SystemContext Register content at time of the exception\r
247 **/\r
248VOID\r
249EFIAPI\r
250ReadGeneralRegisters ( \r
251 IN EFI_SYSTEM_CONTEXT SystemContext\r
252 )\r
253{\r
254 UINTN Index;\r
255 // a UINT32 takes 8 ascii characters\r
256 CHAR8 OutBuffer[(sizeof (gRegisterOffsets) * 2) + 1];\r
257 CHAR8 *OutBufPtr;\r
258 \r
259 // It is not safe to allocate pool here....\r
260 OutBufPtr = OutBuffer;\r
261 for (Index = 0; Index < (sizeof (gRegisterOffsets)/sizeof (UINTN)); Index++) {\r
262 OutBufPtr = BasicReadRegister (SystemContext, Index, OutBufPtr);\r
263 }\r
264 \r
265 *OutBufPtr = '\0';\r
266 SendPacket(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
278BasicWriteRegister (\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 >= (sizeof (gRegisterOffsets)/sizeof (UINTN))) {\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 = (sizeof (gRegisterOffsets)/sizeof (UINTN));\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\r
392\r
393\r
394/** ‘c [addr ]’ \r
395 Continue. addr is Address to resume. If addr is omitted, resume at current \r
396 Address.\r
397 \r
398 @param SystemContext Register content at time of the exception \r
399 **/\r
400VOID\r
401EFIAPI\r
402ContinueAtAddress (\r
403 IN EFI_SYSTEM_CONTEXT SystemContext,\r
404 IN CHAR8 *PacketData\r
405 )\r
406{\r
407 if (PacketData[1] != '\0') {\r
408 SystemContext.SystemContextArm->PC = AsciiStrHexToUintn(&PacketData[1]);\r
409 } \r
410}\r
411\r
412\r
413/** ‘s [addr ]’\r
414 Single step. addr is the Address at which to resume. If addr is omitted, resume \r
415 at same Address.\r
416 \r
417 @param SystemContext Register content at time of the exception \r
418 **/\r
419VOID\r
420EFIAPI\r
421SingleStep (\r
422 IN EFI_SYSTEM_CONTEXT SystemContext,\r
423 IN CHAR8 *PacketData\r
424 )\r
425{\r
426 SendNotSupported();\r
427}\r
428\r
429\r
430VOID\r
431EFIAPI\r
432InsertBreakPoint (\r
433 IN EFI_SYSTEM_CONTEXT SystemContext,\r
434 IN CHAR8 *PacketData\r
435 )\r
436{\r
437 SendNotSupported ();\r
438}\r
439\r
440VOID\r
441EFIAPI\r
442RemoveBreakPoint (\r
443 IN EFI_SYSTEM_CONTEXT SystemContext,\r
444 IN CHAR8 *PacketData\r
445 )\r
446{\r
447 SendNotSupported ();\r
448}\r
449\r
450\r
451/**
452 Send the T signal with the given exception type (in gdb order) and possibly
453 with n:r pairs related to the watchpoints
454
455 @param SystemContext Register content at time of the exception
456 @param GdbExceptionType GDB exception type
457 **/
458VOID
459ProcessorSendTSignal (
460 IN EFI_SYSTEM_CONTEXT SystemContext,
461 IN UINT8 GdbExceptionType,
462 IN OUT CHAR8 *TSignalPtr,
463 IN UINTN SizeOfBuffer
464 )
465{
466 *TSignalPtr = '\0';
467}
468\r
bb5127ae 469/**\r
470 FIQ state is only changed by FIQ exception. We don't want to take FIQ\r
471 ticks in the GDB stub. The stub disables FIQ on entry, but this is the \r
472 third instruction that executes in the execption handler. Thus we have\r
473 a crack we need to test for.\r
474\r
475 @param PC PC of execption\r
476\r
477 @return TRUE We are in the GDB stub exception preamble \r
478 @return FALSE We are not in GDB stub code\r
479 **/
480BOOLEAN
481InFiqCrack (
482 IN UINT32 PC
483 )
484{
485 UINT32 VectorBase = PcdGet32 (PcdCpuVectorBaseAddress);
486 UINT32 Length = (UINTN)ExceptionHandlersEnd - (UINTN)ExceptionHandlersStart;
487
488 if ((PC >= VectorBase) && (PC <= (VectorBase + Length))) {
489 return TRUE;
490 }
491
492 return FALSE;
493}
494\r
495\r
969eba7b 496/**\r
497 Check to see if this exception is related to ctrl-c handling.\r
498\r
499 In this scheme we dedicate FIQ to the ctrl-c handler so it is \r
500 independent of the rest of the system. \r
501 \r
502 SaveAndSetDebugTimerInterrupt () can be used to \r
503\r
504 @param ExceptionType Exception that is being processed\r
505 @param SystemContext Register content at time of the exception \r
506\r
507 @return TRUE This was a ctrl-c check that did not find a ctrl-c\r
508 @return FALSE This was not a ctrl-c check or some one hit ctrl-c\r
509 **/\r
510BOOLEAN\r
511ProcessorControlC ( \r
512 IN EFI_EXCEPTION_TYPE ExceptionType, \r
513 IN OUT EFI_SYSTEM_CONTEXT SystemContext \r
514 )\r
515{\r
bb5127ae 516 CHAR8 Char;\r
969eba7b 517 BOOLEAN Return = TRUE;\r
518\r
519 if (ExceptionType != EXCEPT_ARM_FIQ) {\r
520 // Skip it as it is not related to ctrl-c\r
521 return FALSE;\r
522 }\r
523\r
bb5127ae 524 if (InFiqCrack (SystemContext.SystemContextArm->PC)) {\r
525 // We are in our own interrupt preable, so skip this tick.\r
526 // We never want to let gdb see the debug stub running if we can help it\r
527 return FALSE;\r
528 }\r
529\r
969eba7b 530 while (TRUE) {
531 if (!GdbIsCharAvailable ()) {
532 //
533 // No characters are pending so exit the loop
534 //
535 Return = TRUE;
536 break;
537 }
538
bb5127ae 539 Char = GdbGetChar ();
540 if (Char == 0x03) {
969eba7b 541 //
542 // We have a ctrl-c so exit and process exception for ctrl-c
543 //
544 Return = FALSE;
545 break;
546 }
547 }
548\r
549 DebugAgentTimerEndOfInterrupt ();\r
550\r
551 // Force an exit from the exception handler as we are done\r
552 return Return;\r
553}\r
554\r
555\r
556/**\r
557 Enable/Disable the interrupt of debug timer and return the interrupt state\r
558 prior to the operation.\r
559\r
560 If EnableStatus is TRUE, enable the interrupt of debug timer.\r
561 If EnableStatus is FALSE, disable the interrupt of debug timer.\r
562\r
563 @param[in] EnableStatus Enable/Disable.\r
564\r
bb5127ae 565 @retval TRUE Debug timer interrupt were enabled on entry to this call.\r
566 @retval FALSE Debug timer interrupt were disabled on entry to this call.\r
969eba7b 567\r
568**/\r
569BOOLEAN\r
570EFIAPI\r
571SaveAndSetDebugTimerInterrupt (\r
572 IN BOOLEAN EnableStatus\r
573 )\r
574{\r
575 BOOLEAN FiqEnabled;\r
576\r
577 FiqEnabled = ArmGetFiqState ();\r
578\r
579 if (EnableStatus) {\r
bb5127ae 580 DebugAgentTimerSetPeriod (PcdGet32 (PcdGdbTimerPeriodMilliseconds));\r
969eba7b 581 ArmEnableFiq ();\r
582 } else {\r
583 DebugAgentTimerSetPeriod (0);\r
584 ArmDisableFiq ();\r
585 }\r
586\r
587 return FiqEnabled;\r
588}\r
589\r
bb5127ae 590\r
591\r
969eba7b 592VOID\r
593GdbFPutString (\r
594 IN CHAR8 *String\r
595 );\r
596\r
597/**\r
598 Initialize debug agent.\r
599\r
600 This function is used to set up debug enviroment. It may enable interrupts.\r
601\r
602 @param[in] InitFlag Init flag is used to decide initialize process.\r
603 @param[in] Context Context needed according to InitFlag, it was optional.\r
604\r
605**/\r
606VOID\r
607EFIAPI\r
608InitializeDebugAgent (\r
609 IN UINT32 InitFlag,\r
610 IN VOID *Context OPTIONAL\r
611 )\r
612{
613 UINTN Offset;\r
614 UINTN Length;\r
615 BOOLEAN IrqEnabled;\r
969eba7b 616 UINT32 *VectorBase;\r
617\r
bb5127ae 618
969eba7b 619 //\r
620 // Disable interrupts\r
621 //\r
622 IrqEnabled = ArmGetInterruptState ();\r
623 ArmDisableInterrupts ();\r
969eba7b 624 ArmDisableFiq ();\r
625\r
626 //\r
627 // Copy an implementation of the ARM exception vectors to PcdCpuVectorBaseAddress.\r
628 //\r
629 Length = (UINTN)ExceptionHandlersEnd - (UINTN)ExceptionHandlersStart;\r
630\r
631 //\r
632 // Reserve space for the exception handlers\r
633 //\r
634 VectorBase = (UINT32 *)(UINTN)PcdGet32 (PcdCpuVectorBaseAddress);\r
635\r
636\r
637 // Copy our assembly code into the page that contains the exception vectors. \r
638 CopyMem ((VOID *)VectorBase, (VOID *)ExceptionHandlersStart, Length);\r
639\r
640 //\r
641 // Patch in the common Assembly exception handler\r
642 //\r
643 Offset = (UINTN)CommonExceptionEntry - (UINTN)ExceptionHandlersStart;\r
644 *(UINTN *) (((UINT8 *)VectorBase) + Offset) = (UINTN)AsmCommonExceptionEntry;\r
645\r
646 // Flush Caches since we updated executable stuff\r
647 InvalidateInstructionCacheRange ((VOID *)PcdGet32(PcdCpuVectorBaseAddress), Length);\r
648\r
bb5127ae 649 // setup a timer so gdb can break in via ctrl-c\r
969eba7b 650 DebugAgentTimerIntialize ();\r
651\r
969eba7b 652 if (IrqEnabled) {\r
653 ArmEnableInterrupts ();\r
654 }\r
655\r
656 return;\r
657}\r
658\r