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