]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - EmbeddedPkg/Library/GdbDebugAgent/Arm/Processor.c
ARM Packages: Corrected non-DOS line endings
[mirror_edk2.git] / EmbeddedPkg / Library / GdbDebugAgent / Arm / Processor.c
... / ...
CommitLineData
1/** @file\r
2 Processor specific parts of the GDB stub\r
3\r
4 Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>\r
5 \r
6 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/PrintLib.h>\r
19#include <Library/ArmLib.h>\r
20\r
21//\r
22// Externs from the exception handler assembly file\r
23//\r
24VOID\r
25ExceptionHandlersStart (\r
26 VOID\r
27 );\r
28\r
29VOID\r
30ExceptionHandlersEnd (\r
31 VOID\r
32 );\r
33\r
34VOID\r
35CommonExceptionEntry (\r
36 VOID\r
37 );\r
38\r
39VOID\r
40AsmCommonExceptionEntry (\r
41 VOID\r
42 );\r
43\r
44\r
45//\r
46// Array of exception types that need to be hooked by the debugger\r
47// (efi, gdb) //efi number\r
48//\r
49EFI_EXCEPTION_TYPE_ENTRY gExceptionType[] = {\r
50 { EXCEPT_ARM_SOFTWARE_INTERRUPT, GDB_SIGTRAP },\r
51 { EXCEPT_ARM_UNDEFINED_INSTRUCTION, GDB_SIGTRAP }, \r
52 { EXCEPT_ARM_PREFETCH_ABORT, GDB_SIGTRAP }, \r
53 { EXCEPT_ARM_DATA_ABORT, GDB_SIGTRAP }, // GDB_SIGEMT\r
54 { EXCEPT_ARM_RESERVED, GDB_SIGTRAP }, // GDB_SIGILL\r
55 { EXCEPT_ARM_FIQ, GDB_SIGINT } // Used for ctrl-c\r
56};\r
57\r
58// Shut up some annoying RVCT warnings\r
59#ifdef __CC_ARM\r
60#pragma diag_suppress 1296\r
61#endif\r
62\r
63UINTN gRegisterOffsets[] = {\r
64 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R0),\r
65 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R1),\r
66 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R2),\r
67 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R3),\r
68 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R4),\r
69 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R5),\r
70 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R6),\r
71 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R7),\r
72 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R8),\r
73 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R9),\r
74 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R10),\r
75 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R11),\r
76 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R12),\r
77 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, SP),\r
78 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, LR),\r
79 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, PC),\r
80 0x00000F01, // f0\r
81 0x00000F02,\r
82 0x00000F03,\r
83 0x00000F11, // f1\r
84 0x00000F12,\r
85 0x00000F13,\r
86 0x00000F21, // f2\r
87 0x00000F22,\r
88 0x00000F23,\r
89 0x00000F31, // f3\r
90 0x00000F32,\r
91 0x00000F33,\r
92 0x00000F41, // f4\r
93 0x00000F42,\r
94 0x00000F43,\r
95 0x00000F51, // f5\r
96 0x00000F52,\r
97 0x00000F53,\r
98 0x00000F61, // f6\r
99 0x00000F62,\r
100 0x00000F63,\r
101 0x00000F71, // f7\r
102 0x00000F72,\r
103 0x00000F73,\r
104 0x00000FFF, // fps\r
105 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, CPSR)\r
106};\r
107\r
108// restore warnings for RVCT\r
109#ifdef __CC_ARM\r
110#pragma diag_default 1296\r
111#endif\r
112\r
113\r
114/**\r
115 Return the number of entries in the gExceptionType[]\r
116 \r
117 @retval UINTN, the number of entries in the gExceptionType[] array. \r
118 **/\r
119UINTN\r
120MaxEfiException (\r
121 VOID\r
122 )\r
123{\r
124 return sizeof (gExceptionType)/sizeof (EFI_EXCEPTION_TYPE_ENTRY);\r
125}\r
126\r
127\r
128\r
129\r
130/**\r
131 Check to see if the ISA is supported. \r
132 ISA = Instruction Set Architecture\r
133\r
134 @retval TRUE if Isa is supported \r
135\r
136**/\r
137BOOLEAN\r
138CheckIsa (\r
139 IN EFI_INSTRUCTION_SET_ARCHITECTURE Isa\r
140 )\r
141{\r
142 if (Isa == IsaArm) {\r
143 return TRUE;\r
144 } else {\r
145 return FALSE;\r
146 }\r
147}\r
148\r
149\r
150/**\r
151 This takes in the register number and the System Context, and returns a pointer to the RegNumber-th register in gdb ordering\r
152 It is, by default, set to find the register pointer of the ARM member\r
153 @param SystemContext Register content at time of the exception \r
154 @param RegNumber The register to which we want to find a pointer\r
155 @retval the pointer to the RegNumber-th pointer\r
156 **/ \r
157UINTN *\r
158FindPointerToRegister(\r
159 IN EFI_SYSTEM_CONTEXT SystemContext,\r
160 IN UINTN RegNumber \r
161 )\r
162{\r
163 UINT8 *TempPtr;\r
164 ASSERT(gRegisterOffsets[RegNumber] < 0xF00);\r
165 TempPtr = ((UINT8 *)SystemContext.SystemContextArm) + gRegisterOffsets[RegNumber];\r
166 return (UINT32 *)TempPtr;\r
167}\r
168\r
169\r
170/**\r
171 Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr\r
172 @param SystemContext Register content at time of the exception\r
173 @param RegNumber the number of the register that we want to read\r
174 @param OutBufPtr pointer to the output buffer's end. the new data will be added from this point on.\r
175 @retval the pointer to the next character of the output buffer that is available to be written on.\r
176 **/\r
177CHAR8 *\r
178BasicReadRegister (\r
179 IN EFI_SYSTEM_CONTEXT SystemContext,\r
180 IN UINTN RegNumber,\r
181 IN CHAR8 *OutBufPtr\r
182 )\r
183{\r
184 UINTN RegSize;\r
185 CHAR8 Char;\r
186 \r
187 if (gRegisterOffsets[RegNumber] > 0xF00) {\r
188 AsciiSPrint(OutBufPtr, 9, "00000000");\r
189 OutBufPtr += 8;\r
190 return OutBufPtr;\r
191 }\r
192\r
193 RegSize = 0;\r
194 while (RegSize < 32) {\r
195 Char = mHexToStr[(UINT8)((*FindPointerToRegister(SystemContext, RegNumber) >> (RegSize+4)) & 0xf)];\r
196 if ((Char >= 'A') && (Char <= 'F')) {\r
197 Char = Char - 'A' + 'a';\r
198 }\r
199 *OutBufPtr++ = Char;\r
200 \r
201 Char = mHexToStr[(UINT8)((*FindPointerToRegister(SystemContext, RegNumber) >> RegSize) & 0xf)];\r
202 if ((Char >= 'A') && (Char <= 'F')) {\r
203 Char = Char - 'A' + 'a';\r
204 }\r
205 *OutBufPtr++ = Char;\r
206 \r
207 RegSize = RegSize + 8;\r
208 }\r
209 return OutBufPtr;\r
210}\r
211\r
212\r
213/**\r
214 Reads the n-th register's value into an output buffer and sends it as a packet \r
215 @param SystemContext Register content at time of the exception\r
216 @param InBuffer Pointer to the input buffer received from gdb server\r
217 **/\r
218VOID\r
219ReadNthRegister (\r
220 IN EFI_SYSTEM_CONTEXT SystemContext,\r
221 IN CHAR8 *InBuffer\r
222 )\r
223{\r
224 UINTN RegNumber;\r
225 CHAR8 OutBuffer[9]; // 1 reg=8 hex chars, and the end '\0' (escape seq)\r
226 CHAR8 *OutBufPtr; // pointer to the output buffer\r
227 \r
228 RegNumber = AsciiStrHexToUintn (&InBuffer[1]);\r
229 \r
230 if (RegNumber >= (sizeof (gRegisterOffsets)/sizeof (UINTN))) {\r
231 SendError (GDB_EINVALIDREGNUM); \r
232 return;\r
233 }\r
234 \r
235 OutBufPtr = OutBuffer;\r
236 OutBufPtr = BasicReadRegister (SystemContext, RegNumber, OutBufPtr);\r
237 \r
238 *OutBufPtr = '\0'; // the end of the buffer\r
239 SendPacket(OutBuffer);\r
240}\r
241\r
242\r
243/**\r
244 Reads the general registers into an output buffer and sends it as a packet \r
245 @param SystemContext Register content at time of the exception\r
246 **/\r
247VOID\r
248EFIAPI\r
249ReadGeneralRegisters ( \r
250 IN EFI_SYSTEM_CONTEXT SystemContext\r
251 )\r
252{\r
253 UINTN Index;\r
254 // a UINT32 takes 8 ascii characters\r
255 CHAR8 OutBuffer[(sizeof (gRegisterOffsets) * 2) + 1];\r
256 CHAR8 *OutBufPtr;\r
257 \r
258 // It is not safe to allocate pool here....\r
259 OutBufPtr = OutBuffer;\r
260 for (Index = 0; Index < (sizeof (gRegisterOffsets)/sizeof (UINTN)); Index++) {\r
261 OutBufPtr = BasicReadRegister (SystemContext, Index, OutBufPtr);\r
262 }\r
263 \r
264 *OutBufPtr = '\0';\r
265 SendPacket(OutBuffer);\r
266}\r
267\r
268\r
269/**\r
270 Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr\r
271 @param SystemContext Register content at time of the exception\r
272 @param RegNumber the number of the register that we want to write\r
273 @param InBufPtr pointer to the output buffer. the new data will be extracted from the input buffer from this point on.\r
274 @retval the pointer to the next character of the input buffer that can be used\r
275 **/\r
276CHAR8 *\r
277BasicWriteRegister (\r
278 IN EFI_SYSTEM_CONTEXT SystemContext,\r
279 IN UINTN RegNumber,\r
280 IN CHAR8 *InBufPtr\r
281 )\r
282{\r
283 UINTN RegSize;\r
284 UINTN TempValue; // the value transferred from a hex char\r
285 UINT32 NewValue; // the new value of the RegNumber-th Register\r
286 \r
287 if (gRegisterOffsets[RegNumber] > 0xF00) {\r
288 return InBufPtr + 8;\r
289 }\r
290\r
291 NewValue = 0;\r
292 RegSize = 0;\r
293 while (RegSize < 32) {\r
294 TempValue = HexCharToInt(*InBufPtr++);\r
295 \r
296 if ((INTN)TempValue < 0) {\r
297 SendError (GDB_EBADMEMDATA); \r
298 return NULL;\r
299 }\r
300 \r
301 NewValue += (TempValue << (RegSize+4));\r
302 TempValue = HexCharToInt(*InBufPtr++);\r
303 \r
304 if ((INTN)TempValue < 0) {\r
305 SendError (GDB_EBADMEMDATA); \r
306 return NULL;\r
307 }\r
308 \r
309 NewValue += (TempValue << RegSize); \r
310 RegSize = RegSize + 8;\r
311 }\r
312 *(FindPointerToRegister(SystemContext, RegNumber)) = NewValue;\r
313 return InBufPtr;\r
314}\r
315\r
316\r
317/** ‘P n...=r...’\r
318 Writes the new value of n-th register received into the input buffer to the n-th register\r
319 @param SystemContext Register content at time of the exception\r
320 @param InBuffer Ponter to the input buffer received from gdb server\r
321 **/\r
322VOID\r
323WriteNthRegister (\r
324 IN EFI_SYSTEM_CONTEXT SystemContext,\r
325 IN CHAR8 *InBuffer\r
326 )\r
327{\r
328 UINTN RegNumber;\r
329 CHAR8 RegNumBuffer[MAX_REG_NUM_BUF_SIZE]; // put the 'n..' part of the message into this array\r
330 CHAR8 *RegNumBufPtr;\r
331 CHAR8 *InBufPtr; // pointer to the input buffer\r
332 \r
333 // find the register number to write\r
334 InBufPtr = &InBuffer[1];\r
335 RegNumBufPtr = RegNumBuffer;\r
336 while (*InBufPtr != '=') {\r
337 *RegNumBufPtr++ = *InBufPtr++;\r
338 } \r
339 *RegNumBufPtr = '\0';\r
340 RegNumber = AsciiStrHexToUintn (RegNumBuffer); \r
341 \r
342 // check if this is a valid Register Number\r
343 if (RegNumber >= (sizeof (gRegisterOffsets)/sizeof (UINTN))) {\r
344 SendError (GDB_EINVALIDREGNUM); \r
345 return;\r
346 }\r
347 InBufPtr++; // skips the '=' character\r
348 BasicWriteRegister (SystemContext, RegNumber, InBufPtr);\r
349 SendSuccess();\r
350}\r
351\r
352\r
353/** ‘G XX...’\r
354 Writes the new values received into the input buffer to the general registers\r
355 @param SystemContext Register content at time of the exception\r
356 @param InBuffer Pointer to the input buffer received from gdb server\r
357 **/\r
358\r
359VOID\r
360EFIAPI\r
361WriteGeneralRegisters (\r
362 IN EFI_SYSTEM_CONTEXT SystemContext,\r
363 IN CHAR8 *InBuffer\r
364 )\r
365{\r
366 UINTN i;\r
367 CHAR8 *InBufPtr; /// pointer to the input buffer\r
368 UINTN MinLength;\r
369 UINTN RegisterCount = (sizeof (gRegisterOffsets)/sizeof (UINTN));\r
370\r
371 MinLength = (RegisterCount * 8) + 1; // 'G' plus the registers in ASCII format\r
372 \r
373 if (AsciiStrLen(InBuffer) < MinLength) {\r
374 //Bad message. Message is not the right length \r
375 SendError (GDB_EBADBUFSIZE); \r
376 return;\r
377 }\r
378 \r
379 InBufPtr = &InBuffer[1];\r
380 \r
381 // Read the new values for the registers from the input buffer to an array, NewValueArray.\r
382 // The values in the array are in the gdb ordering\r
383 for(i = 0; i < RegisterCount; i++) {\r
384 InBufPtr = BasicWriteRegister (SystemContext, i, InBufPtr);\r
385 }\r
386 \r
387 SendSuccess ();\r
388}\r
389\r
390\r
391\r
392\r
393/**\r
394 Continue. addr is Address to resume. If addr is omitted, resume at current \r
395 Address.\r
396 \r
397 @param SystemContext Register content at time of the exception \r
398 **/\r
399VOID\r
400EFIAPI\r
401ContinueAtAddress (\r
402 IN EFI_SYSTEM_CONTEXT SystemContext,\r
403 IN CHAR8 *PacketData\r
404 )\r
405{\r
406 if (PacketData[1] != '\0') {\r
407 SystemContext.SystemContextArm->PC = AsciiStrHexToUintn(&PacketData[1]);\r
408 } \r
409}\r
410\r
411\r
412/** ‘s [addr ]’\r
413 Single step. addr is the Address at which to resume. If addr is omitted, resume \r
414 at same Address.\r
415 \r
416 @param SystemContext Register content at time of the exception \r
417 **/\r
418VOID\r
419EFIAPI\r
420SingleStep (\r
421 IN EFI_SYSTEM_CONTEXT SystemContext,\r
422 IN CHAR8 *PacketData\r
423 )\r
424{\r
425 SendNotSupported();\r
426}\r
427\r
428\r
429VOID\r
430EFIAPI\r
431InsertBreakPoint (\r
432 IN EFI_SYSTEM_CONTEXT SystemContext,\r
433 IN CHAR8 *PacketData\r
434 )\r
435{\r
436 SendNotSupported ();\r
437}\r
438\r
439VOID\r
440EFIAPI\r
441RemoveBreakPoint (\r
442 IN EFI_SYSTEM_CONTEXT SystemContext,\r
443 IN CHAR8 *PacketData\r
444 )\r
445{\r
446 SendNotSupported ();\r
447}\r
448\r
449\r
450/**\r
451 Send the T signal with the given exception type (in gdb order) and possibly \r
452 with n:r pairs related to the watchpoints\r
453 \r
454 @param SystemContext Register content at time of the exception\r
455 @param GdbExceptionType GDB exception type\r
456 **/\r
457VOID\r
458ProcessorSendTSignal (\r
459 IN EFI_SYSTEM_CONTEXT SystemContext,\r
460 IN UINT8 GdbExceptionType,\r
461 IN OUT CHAR8 *TSignalPtr,\r
462 IN UINTN SizeOfBuffer\r
463 )\r
464{\r
465 *TSignalPtr = '\0';\r
466}\r
467\r
468/**\r
469 FIQ state is only changed by FIQ exception. We don't want to take FIQ\r
470 ticks in the GDB stub. The stub disables FIQ on entry, but this is the \r
471 third instruction that executes in the execption handler. Thus we have\r
472 a crack we need to test for.\r
473\r
474 @param PC PC of execption\r
475\r
476 @return TRUE We are in the GDB stub exception preamble \r
477 @return FALSE We are not in GDB stub code\r
478 **/\r
479BOOLEAN\r
480InFiqCrack (\r
481 IN UINT32 PC\r
482 )\r
483{\r
484 UINT32 VectorBase = PcdGet32 (PcdCpuVectorBaseAddress);\r
485 UINT32 Length = (UINTN)ExceptionHandlersEnd - (UINTN)ExceptionHandlersStart;\r
486\r
487 if ((PC >= VectorBase) && (PC <= (VectorBase + Length))) {\r
488 return TRUE;\r
489 }\r
490\r
491 return FALSE;\r
492}\r
493\r
494\r
495/**\r
496 Check to see if this exception is related to ctrl-c handling.\r
497\r
498 In this scheme we dedicate FIQ to the ctrl-c handler so it is \r
499 independent of the rest of the system. \r
500 \r
501 SaveAndSetDebugTimerInterrupt () can be used to \r
502\r
503 @param ExceptionType Exception that is being processed\r
504 @param SystemContext Register content at time of the exception \r
505\r
506 @return TRUE This was a ctrl-c check that did not find a ctrl-c\r
507 @return FALSE This was not a ctrl-c check or some one hit ctrl-c\r
508 **/\r
509BOOLEAN\r
510ProcessorControlC ( \r
511 IN EFI_EXCEPTION_TYPE ExceptionType, \r
512 IN OUT EFI_SYSTEM_CONTEXT SystemContext \r
513 )\r
514{\r
515 CHAR8 Char;\r
516 BOOLEAN Return = TRUE;\r
517\r
518 if (ExceptionType != EXCEPT_ARM_FIQ) {\r
519 // Skip it as it is not related to ctrl-c\r
520 return FALSE;\r
521 }\r
522\r
523 if (InFiqCrack (SystemContext.SystemContextArm->PC)) {\r
524 // We are in our own interrupt preable, so skip this tick.\r
525 // We never want to let gdb see the debug stub running if we can help it\r
526 return FALSE;\r
527 }\r
528\r
529 while (TRUE) {\r
530 if (!GdbIsCharAvailable ()) {\r
531 //\r
532 // No characters are pending so exit the loop\r
533 //\r
534 Return = TRUE;\r
535 break;\r
536 }\r
537 \r
538 Char = GdbGetChar ();\r
539 if (Char == 0x03) {\r
540 //\r
541 // We have a ctrl-c so exit and process exception for ctrl-c\r
542 //\r
543 Return = FALSE;\r
544 break;\r
545 }\r
546 }\r
547\r
548 DebugAgentTimerEndOfInterrupt ();\r
549\r
550 // Force an exit from the exception handler as we are done\r
551 return Return;\r
552}\r
553\r
554\r
555/**\r
556 Enable/Disable the interrupt of debug timer and return the interrupt state\r
557 prior to the operation.\r
558\r
559 If EnableStatus is TRUE, enable the interrupt of debug timer.\r
560 If EnableStatus is FALSE, disable the interrupt of debug timer.\r
561\r
562 @param[in] EnableStatus Enable/Disable.\r
563\r
564 @retval TRUE Debug timer interrupt were enabled on entry to this call.\r
565 @retval FALSE Debug timer interrupt were disabled on entry to this call.\r
566\r
567**/\r
568BOOLEAN\r
569EFIAPI\r
570SaveAndSetDebugTimerInterrupt (\r
571 IN BOOLEAN EnableStatus\r
572 )\r
573{\r
574 BOOLEAN FiqEnabled;\r
575\r
576 FiqEnabled = ArmGetFiqState ();\r
577\r
578 if (EnableStatus) {\r
579 DebugAgentTimerSetPeriod (PcdGet32 (PcdGdbTimerPeriodMilliseconds));\r
580 ArmEnableFiq ();\r
581 } else {\r
582 DebugAgentTimerSetPeriod (0);\r
583 ArmDisableFiq ();\r
584 }\r
585\r
586 return FiqEnabled;\r
587}\r
588\r
589\r
590\r
591VOID\r
592GdbFPutString (\r
593 IN CHAR8 *String\r
594 );\r
595\r
596/**\r
597 Initialize debug agent.\r
598\r
599 This function is used to set up debug environment to support source level debugging.\r
600 If certain Debug Agent Library instance has to save some private data in the stack,\r
601 this function must work on the mode that doesn't return to the caller, then\r
602 the caller needs to wrap up all rest of logic after InitializeDebugAgent() into one\r
603 function and pass it into InitializeDebugAgent(). InitializeDebugAgent() is\r
604 responsible to invoke the passing-in function at the end of InitializeDebugAgent().\r
605\r
606 If the parameter Function is not NULL, Debug Agent Libary instance will invoke it by\r
607 passing in the Context to be its parameter.\r
608\r
609 If Function() is NULL, Debug Agent Library instance will return after setup debug\r
610 environment.\r
611\r
612 @param[in] InitFlag Init flag is used to decide the initialize process.\r
613 @param[in] Context Context needed according to InitFlag; it was optional.\r
614 @param[in] Function Continue function called by debug agent library; it was\r
615 optional.\r
616\r
617**/\r
618VOID\r
619EFIAPI\r
620InitializeDebugAgent (\r
621 IN UINT32 InitFlag,\r
622 IN VOID *Context, OPTIONAL\r
623 IN DEBUG_AGENT_CONTINUE Function OPTIONAL\r
624 )\r
625{ \r
626 UINTN Offset;\r
627 UINTN Length;\r
628 BOOLEAN IrqEnabled;\r
629 UINT32 *VectorBase;\r
630\r
631\r
632 //\r
633 // Disable interrupts\r
634 //\r
635 IrqEnabled = ArmGetInterruptState ();\r
636 ArmDisableInterrupts ();\r
637 ArmDisableFiq ();\r
638\r
639 //\r
640 // Copy an implementation of the ARM exception vectors to PcdCpuVectorBaseAddress.\r
641 //\r
642 Length = (UINTN)ExceptionHandlersEnd - (UINTN)ExceptionHandlersStart;\r
643\r
644 //\r
645 // Reserve space for the exception handlers\r
646 //\r
647 VectorBase = (UINT32 *)(UINTN)PcdGet32 (PcdCpuVectorBaseAddress);\r
648\r
649\r
650 // Copy our assembly code into the page that contains the exception vectors. \r
651 CopyMem ((VOID *)VectorBase, (VOID *)ExceptionHandlersStart, Length);\r
652\r
653 //\r
654 // Patch in the common Assembly exception handler\r
655 //\r
656 Offset = (UINTN)CommonExceptionEntry - (UINTN)ExceptionHandlersStart;\r
657 *(UINTN *) (((UINT8 *)VectorBase) + Offset) = (UINTN)AsmCommonExceptionEntry;\r
658\r
659 // Flush Caches since we updated executable stuff\r
660 InvalidateInstructionCacheRange ((VOID *)PcdGet32(PcdCpuVectorBaseAddress), Length);\r
661\r
662 // setup a timer so gdb can break in via ctrl-c\r
663 DebugAgentTimerIntialize ();\r
664\r
665 if (IrqEnabled) {\r
666 ArmEnableInterrupts ();\r
667 }\r
668\r
669 if (Function != NULL) {\r
670 Function (Context);\r
671 }\r
672\r
673 return;\r
674}\r
675\r