Add X64 support for DebugSupport driver.
[mirror_edk2.git] / EdkModulePkg / Universal / DebugSupport / Dxe / ipf / plDebugSupport.c
CommitLineData
5fd59c65 1/**@file\r
2 IPF specific debug support functions\r
878ddf1f 3\r
4Copyright (c) 2006, Intel Corporation \r
5All rights reserved. This program and the accompanying materials \r
6are licensed and made available under the terms and conditions of the BSD License \r
7which accompanies this distribution. The full text of the license may be found at \r
8http://opensource.org/licenses/bsd-license.php \r
9 \r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
12\r
5fd59c65 13**/\r
878ddf1f 14\r
15//\r
16// private header files\r
17//\r
18#include "plDebugSupport.h"\r
19\r
20typedef struct {\r
21 UINT64 low;\r
22 UINT64 high;\r
23} BUNDLE;\r
24\r
25//\r
26// number of bundles to swap in ivt\r
27//\r
28#define NUM_BUNDLES_IN_STUB 5\r
29#define NUM_IVT_ENTRIES 64\r
30\r
31typedef struct {\r
32 BUNDLE OrigBundles[NUM_BUNDLES_IN_STUB];\r
33 VOID (*RegisteredCallback) ();\r
34} IVT_ENTRY;\r
35\r
36STATIC\r
37EFI_STATUS\r
38ManageIvtEntryTable (\r
39 IN EFI_EXCEPTION_TYPE ExceptionType,\r
40 IN BUNDLE NewBundles[4],\r
41 IN VOID (*NewCallback) ()\r
42 );\r
43\r
44STATIC\r
45VOID\r
46HookEntry (\r
47 IN EFI_EXCEPTION_TYPE ExceptionType,\r
48 IN BUNDLE NewBundles[4],\r
49 IN VOID (*NewCallback) ()\r
50 );\r
51\r
52STATIC\r
53VOID\r
54UnhookEntry (\r
55 IN EFI_EXCEPTION_TYPE ExceptionType\r
56 );\r
57\r
58STATIC\r
59VOID\r
60ChainExternalInterrupt (\r
61 IN VOID (*NewCallback) ()\r
62 );\r
63\r
64STATIC\r
65VOID\r
66UnchainExternalInterrupt (\r
67 VOID\r
68 );\r
69\r
70STATIC\r
71VOID\r
72GetHandlerEntryPoint (\r
73 UINTN HandlerIndex,\r
74 VOID **EntryPoint\r
75 );\r
76\r
77IVT_ENTRY IvtEntryTable[NUM_IVT_ENTRIES];\r
78\r
79//\r
80// IPF context record is overallocated by 512 bytes to guarantee a 512 byte alignment exists\r
81// within the buffer and still have a large enough buffer to hold a whole IPF context record.\r
82//\r
83UINT8 IpfContextBuf[sizeof (EFI_SYSTEM_CONTEXT_IPF) + 512];\r
84\r
85//\r
86// The PatchSaveBuffer is used to store the original bundles from the IVT where it is patched\r
87// with the common handler.\r
88//\r
89UINT8 PatchSaveBuffer[0x400];\r
90UINTN ExternalInterruptCount;\r
91\r
92EFI_STATUS\r
93plInitializeDebugSupportDriver (\r
94 VOID\r
95 )\r
96/*++\r
97\r
98Routine Description:\r
99 IPF specific DebugSupport driver initialization. Must be public because it's\r
100 referenced from DebugSupport.c\r
101\r
102Arguments:\r
103\r
104Returns:\r
105\r
106 EFI_SUCCESS\r
107\r
108--*/\r
109{\r
110 gBS->SetMem (IvtEntryTable, sizeof (IvtEntryTable), 0);\r
111 ExternalInterruptCount = 0;\r
112 return EFI_SUCCESS;\r
113}\r
114\r
115EFI_STATUS\r
116EFIAPI\r
117plUnloadDebugSupportDriver (\r
118 IN EFI_HANDLE ImageHandle\r
119 )\r
120/*++\r
121\r
122Routine Description:\r
123 Unload handler that is called during UnloadImage() - deallocates pool memory\r
124 used by the driver. Must be public because it's referenced from DebugSuport.c\r
125\r
126Arguments:\r
5fd59c65 127 ImageHandle - Image handle\r
878ddf1f 128\r
129Returns:\r
130\r
131 EFI_STATUS - anything other than EFI_SUCCESS indicates the callback was not registered.\r
132\r
133--*/\r
878ddf1f 134{\r
135 EFI_EXCEPTION_TYPE ExceptionType;\r
136\r
137 for (ExceptionType = 0; ExceptionType < NUM_IVT_ENTRIES; ExceptionType++) {\r
138 ManageIvtEntryTable (ExceptionType, NULL, NULL);\r
139 }\r
140\r
141 return EFI_SUCCESS;\r
142}\r
143\r
144VOID\r
145CommonHandler (\r
146 IN EFI_EXCEPTION_TYPE ExceptionType,\r
147 IN EFI_SYSTEM_CONTEXT Context\r
148 )\r
149/*++\r
150\r
151Routine Description:\r
152 C routine that is called for all registered exceptions. This is the main\r
153 exception dispatcher. Must be public because it's referenced from AsmFuncs.s.\r
154\r
155Arguments:\r
5fd59c65 156 ExceptionType - Exception Type\r
157 Context - System Context\r
878ddf1f 158\r
159Returns:\r
160\r
161 Nothing\r
162 \r
163--*/\r
878ddf1f 164{\r
165 static BOOLEAN InHandler = FALSE;\r
166\r
2ce31132 167 DEBUG_CODE_BEGIN ();\r
878ddf1f 168 if (InHandler) {\r
5fd59c65 169 DEBUG ((EFI_D_INFO, "ERROR: Re-entered debugger!\n"\r
878ddf1f 170 " ExceptionType == %X\n"\r
171 " Context == %X\n"\r
172 " Context.SystemContextIpf->CrIip == %X\n"\r
173 " Context.SystemContextIpf->CrIpsr == %X\n"\r
174 " InHandler == %X\n",\r
175 ExceptionType, \r
176 Context, \r
177 Context.SystemContextIpf->CrIip,\r
178 Context.SystemContextIpf->CrIpsr,\r
5fd59c65 179 InHandler));\r
878ddf1f 180 }\r
2ce31132 181 DEBUG_CODE_END ();\r
182\r
878ddf1f 183 ASSERT (!InHandler);\r
184 InHandler = TRUE;\r
185 if (IvtEntryTable[ExceptionType].RegisteredCallback != NULL) {\r
186 if (ExceptionType != EXCEPT_IPF_EXTERNAL_INTERRUPT) {\r
187 IvtEntryTable[ExceptionType].RegisteredCallback (ExceptionType, Context.SystemContextIpf);\r
188 } else {\r
189 IvtEntryTable[ExceptionType].RegisteredCallback (Context.SystemContextIpf);\r
190 }\r
191 } else {\r
192 ASSERT (0);\r
193 }\r
194\r
195 InHandler = FALSE;\r
196}\r
197\r
198STATIC\r
199VOID\r
200GetHandlerEntryPoint (\r
201 UINTN HandlerIndex,\r
202 VOID **EntryPoint\r
203 )\r
204/*++\r
205\r
206Routine Description:\r
207 Given an integer number, return the physical address of the entry point in the IFT\r
208 \r
209Arguments:\r
5fd59c65 210 HandlerIndex - Index of the Handler \r
211 EntryPoint - IFT Entrypoint\r
878ddf1f 212\r
213Returns:\r
214\r
215 Nothing\r
216 \r
217--*/\r
878ddf1f 218{\r
219 UINT8 *TempPtr;\r
220\r
221 //\r
222 // get base address of IVT\r
223 //\r
224 TempPtr = GetIva ();\r
225\r
226 if (HandlerIndex < 20) {\r
227 //\r
228 // first 20 provide 64 bundles per vector\r
229 //\r
230 TempPtr += 0x400 * HandlerIndex;\r
231 } else {\r
232 //\r
233 // the rest provide 16 bundles per vector\r
234 //\r
235 TempPtr += 0x5000 + 0x100 * (HandlerIndex - 20);\r
236 }\r
237\r
238 *EntryPoint = (VOID *) TempPtr;\r
239}\r
240\r
241STATIC\r
242EFI_STATUS\r
243ManageIvtEntryTable (\r
244 IN EFI_EXCEPTION_TYPE ExceptionType,\r
245 IN BUNDLE NewBundles[NUM_BUNDLES_IN_STUB],\r
246 IN VOID (*NewCallback) ()\r
247 )\r
248/*++\r
249\r
250Routine Description:\r
251 This is the worker function that installs and removes all handlers\r
252 \r
253Arguments:\r
5fd59c65 254 ExceptionType - Exception Type\r
255 NewBundles - New Boundles\r
256 NewCallback - New Callback\r
878ddf1f 257\r
258Returns:\r
259\r
260 EFI_STATUS - any return other than EFI_SUCCESS indicates the request was not\r
261 satisfied.\r
5fd59c65 262 EFI_ALEADY_STARTED - Ivt already hooked.\r
878ddf1f 263 \r
264--*/\r
878ddf1f 265{\r
266 BUNDLE *B0Ptr;\r
267 UINT64 InterruptFlags;\r
268 EFI_TPL OldTpl;\r
269\r
270 //\r
271 // Get address of bundle 0\r
272 //\r
273 GetHandlerEntryPoint (ExceptionType, (VOID **) &B0Ptr);\r
274\r
275 if (IvtEntryTable[ExceptionType].RegisteredCallback != NULL) {\r
276 //\r
277 // we've already installed to this vector\r
278 //\r
279 if (NewCallback != NULL) {\r
280 //\r
281 // if the input handler is non-null, error\r
282 //\r
283 return EFI_ALREADY_STARTED;\r
284 } else {\r
285 //\r
286 // else remove the previously installed handler\r
287 //\r
288 OldTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL);\r
289 InterruptFlags = ProgramInterruptFlags (DISABLE_INTERRUPTS);\r
290 if (ExceptionType == EXCEPT_IPF_EXTERNAL_INTERRUPT) {\r
291 UnchainExternalInterrupt ();\r
292 } else {\r
293 UnhookEntry (ExceptionType);\r
294 }\r
295\r
296 ProgramInterruptFlags (InterruptFlags);\r
297 gBS->RestoreTPL (OldTpl);\r
298 //\r
299 // re-init IvtEntryTable\r
300 //\r
301 gBS->SetMem (&IvtEntryTable[ExceptionType], sizeof (IVT_ENTRY), 0);\r
302 }\r
303 } else {\r
304 //\r
305 // no user handler installed on this vector\r
306 //\r
307 if (NewCallback != NULL) {\r
308 OldTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL);\r
309 InterruptFlags = ProgramInterruptFlags (DISABLE_INTERRUPTS);\r
310 if (ExceptionType == EXCEPT_IPF_EXTERNAL_INTERRUPT) {\r
311 ChainExternalInterrupt (NewCallback);\r
312 } else {\r
313 HookEntry (ExceptionType, NewBundles, NewCallback);\r
314 }\r
315\r
316 ProgramInterruptFlags (InterruptFlags);\r
317 gBS->RestoreTPL (OldTpl);\r
318 }\r
319 }\r
320\r
321 return EFI_SUCCESS;\r
322}\r
323\r
324STATIC\r
325VOID\r
326HookEntry (\r
327 IN EFI_EXCEPTION_TYPE ExceptionType,\r
328 IN BUNDLE NewBundles[4],\r
329 IN VOID (*NewCallback) ()\r
330 )\r
331/*++\r
332\r
333Routine Description:\r
334 Saves original IVT contents and inserts a few new bundles which are fixed up\r
335 to store the ExceptionType and then call the common handler.\r
336 \r
337Arguments:\r
5fd59c65 338 ExceptionType - Exception Type\r
339 NewBundles - New Boundles\r
340 NewCallback - New Callback\r
878ddf1f 341\r
342Returns:\r
343\r
344 Nothing\r
345 \r
346--*/\r
878ddf1f 347{\r
348 BUNDLE *FixupBundle;\r
349 BUNDLE *B0Ptr;\r
350\r
351 //\r
352 // Get address of bundle 0\r
353 //\r
354 GetHandlerEntryPoint (ExceptionType, (VOID **) &B0Ptr);\r
355\r
356 //\r
357 // copy original bundles from IVT to IvtEntryTable so we can restore them later\r
358 //\r
359 gBS->CopyMem (\r
360 IvtEntryTable[ExceptionType].OrigBundles,\r
361 B0Ptr,\r
362 sizeof (BUNDLE) * NUM_BUNDLES_IN_STUB\r
363 );\r
364 //\r
365 // insert new B0\r
366 //\r
367 gBS->CopyMem (B0Ptr, NewBundles, sizeof (BUNDLE) * NUM_BUNDLES_IN_STUB);\r
368\r
369 //\r
370 // fixup IVT entry so it stores its index and whether or not to chain...\r
371 //\r
372 FixupBundle = B0Ptr + 2;\r
373 FixupBundle->high |= ExceptionType << 36;\r
374\r
375 InstructionCacheFlush (B0Ptr, 5);\r
376 IvtEntryTable[ExceptionType].RegisteredCallback = NewCallback;\r
377}\r
378\r
379STATIC\r
380VOID\r
381UnhookEntry (\r
382 IN EFI_EXCEPTION_TYPE ExceptionType\r
383 )\r
384/*++\r
385\r
386Routine Description:\r
387 Restores original IVT contents when unregistering a callback function\r
388 \r
389Arguments:\r
5fd59c65 390 ExceptionType - Exception Type\r
391 NewBundles - New Boundles\r
392 NewCallback - New Callback\r
878ddf1f 393\r
394Returns:\r
395\r
396 Nothing\r
397 \r
398--*/\r
878ddf1f 399{\r
400 BUNDLE *B0Ptr;\r
401\r
402 //\r
403 // Get address of bundle 0\r
404 //\r
405 GetHandlerEntryPoint (ExceptionType, (VOID **) &B0Ptr);\r
406 //\r
407 // restore original bundles in IVT\r
408 //\r
409 gBS->CopyMem (\r
410 B0Ptr,\r
411 IvtEntryTable[ExceptionType].OrigBundles,\r
412 sizeof (BUNDLE) * NUM_BUNDLES_IN_STUB\r
413 );\r
414 InstructionCacheFlush (B0Ptr, 5);\r
415}\r
416\r
417STATIC\r
418VOID\r
419ChainExternalInterrupt (\r
420 IN VOID (*NewCallback) ()\r
421 )\r
422/*++\r
423\r
424Routine Description:\r
425 Sets up cache flush and calls assembly function to chain external interrupt.\r
426 Records new callback in IvtEntryTable.\r
427 \r
428Arguments:\r
5fd59c65 429 NewCallback - New Callback\r
878ddf1f 430\r
431Returns:\r
432\r
433 Nothing\r
434 \r
435--*/\r
878ddf1f 436{\r
437 VOID *Start;\r
438\r
439 Start = (VOID *) ((UINT8 *) GetIva () + 0x400 * EXCEPT_IPF_EXTERNAL_INTERRUPT + 0x400);\r
440 IvtEntryTable[EXCEPT_IPF_EXTERNAL_INTERRUPT].RegisteredCallback = NewCallback;\r
441 ChainHandler ();\r
442 InstructionCacheFlush (Start, 0x400);\r
443}\r
444\r
445STATIC\r
446VOID\r
447UnchainExternalInterrupt (\r
448 VOID\r
449 )\r
450/*++\r
451\r
452Routine Description:\r
453 Sets up cache flush and calls assembly function to restore external interrupt.\r
454 Removes registered callback from IvtEntryTable.\r
455 \r
456Arguments:\r
457 Nothing\r
458 \r
459Returns:\r
460\r
461 Nothing\r
462 \r
463--*/\r
464{\r
465 VOID *Start;\r
466\r
467 Start = (VOID *) ((UINT8 *) GetIva () + 0x400 * EXCEPT_IPF_EXTERNAL_INTERRUPT + 0x400);\r
468 UnchainHandler ();\r
469 InstructionCacheFlush (Start, 0x400);\r
470 IvtEntryTable[EXCEPT_IPF_EXTERNAL_INTERRUPT].RegisteredCallback = NULL;\r
471}\r
472\r
473//\r
474// The rest of the functions in this file are all member functions for the\r
475// DebugSupport protocol\r
476//\r
477\r
478EFI_STATUS\r
479EFIAPI\r
480GetMaximumProcessorIndex (\r
481 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
482 OUT UINTN *MaxProcessorIndex\r
483 )\r
484/*++\r
485\r
486Routine Description: This is a DebugSupport protocol member function. Hard\r
487 coded to support only 1 processor for now.\r
488\r
489Arguments:\r
5fd59c65 490 This - The DebugSupport instance\r
491 MaxProcessorIndex - The maximuim supported processor index\r
878ddf1f 492\r
5fd59c65 493Returns:\r
494 Always returns EFI_SUCCESS with *MaxProcessorIndex set to 0\r
878ddf1f 495\r
496--*/\r
878ddf1f 497{\r
498 *MaxProcessorIndex = 0;\r
499 return (EFI_SUCCESS);\r
500}\r
501\r
502EFI_STATUS\r
503EFIAPI\r
504RegisterPeriodicCallback (\r
505 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
506 IN UINTN ProcessorIndex,\r
507 IN EFI_PERIODIC_CALLBACK NewPeriodicCallback\r
508 )\r
509/*++\r
510\r
511Routine Description:\r
512 DebugSupport protocol member function\r
513\r
514Arguments:\r
5fd59c65 515 This - The DebugSupport instance\r
516 ProcessorIndex - Which processor the callback applies to.\r
517 PeriodicCallback - Callback function\r
878ddf1f 518\r
519Returns:\r
520\r
521 EFI_STATUS - anything other than EFI_SUCCESS indicates the callback was not registered.\r
522\r
523--*/\r
878ddf1f 524{\r
525 return ManageIvtEntryTable (EXCEPT_IPF_EXTERNAL_INTERRUPT, NULL, NewPeriodicCallback);\r
526}\r
527\r
528EFI_STATUS\r
529EFIAPI\r
530RegisterExceptionCallback (\r
531 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
532 IN UINTN ProcessorIndex,\r
533 IN EFI_EXCEPTION_CALLBACK NewCallback,\r
534 IN EFI_EXCEPTION_TYPE ExceptionType\r
535 )\r
536/*++\r
537\r
538Routine Description:\r
539 DebugSupport protocol member function\r
540\r
541Arguments:\r
5fd59c65 542 This - The DebugSupport instance\r
543 ProcessorIndex - Which processor the callback applies to.\r
544 NewCallback - Callback function\r
545 ExceptionType - Which exception to hook\r
878ddf1f 546\r
547Returns:\r
548\r
549 EFI_STATUS - anything other than EFI_SUCCESS indicates the callback was not registered.\r
550\r
551--*/\r
878ddf1f 552{\r
553 return ManageIvtEntryTable (\r
554 ExceptionType,\r
555 (BUNDLE *) ((EFI_PLABEL *) HookStub)->EntryPoint,\r
556 NewCallback\r
557 );\r
558}\r
559\r
560EFI_STATUS\r
561EFIAPI\r
562InvalidateInstructionCache (\r
563 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
564 IN UINTN ProcessorIndex,\r
565 IN VOID *Start,\r
566 IN UINTN Length\r
567 )\r
568/*++\r
569\r
570Routine Description:\r
571 DebugSupport protocol member function. Calls assembly routine to flush cache.\r
572\r
573Arguments:\r
5fd59c65 574 This - The DebugSupport instance\r
575 ProcessorIndex - Which processor the callback applies to.\r
576 Start - Physical base of the memory range to be invalidated\r
577 Length - mininum number of bytes in instruction cache to invalidate\r
878ddf1f 578\r
579Returns:\r
580 EFI_SUCCESS\r
581\r
582--*/\r
878ddf1f 583{\r
584 InstructionCacheFlush (Start, Length);\r
585 return (EFI_SUCCESS);\r
586}\r