]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/DebugSupportDxe/Ipf/PlDebugSupport.c
code scrub for DebugSpport Module.
[mirror_edk2.git] / MdeModulePkg / Universal / DebugSupportDxe / Ipf / PlDebugSupport.c
CommitLineData
9e604fe4 1/** @file\r
c1f23d63 2 IPF specific debug support functions\r
3\r
19b15d63 4Copyright (c) 2006 - 2008, Intel Corporation \r
c1f23d63 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
13**/\r
14\r
15//\r
16// private header files\r
17//\r
e9f9d09a 18#include "PlDebugSupport.h"\r
c1f23d63 19\r
19b15d63 20BOOLEAN mInHandler = FALSE;\r
21\r
c1f23d63 22//\r
23// number of bundles to swap in ivt\r
24//\r
25#define NUM_BUNDLES_IN_STUB 5\r
26#define NUM_IVT_ENTRIES 64\r
27\r
28typedef struct {\r
29 BUNDLE OrigBundles[NUM_BUNDLES_IN_STUB];\r
30 VOID (*RegisteredCallback) ();\r
31} IVT_ENTRY;\r
32\r
aa79b0b3 33IVT_ENTRY IvtEntryTable[NUM_IVT_ENTRIES];\r
34\r
35//\r
36// IPF context record is overallocated by 512 bytes to guarantee a 512 byte alignment exists\r
37// within the buffer and still have a large enough buffer to hold a whole IPF context record.\r
38//\r
39UINT8 IpfContextBuf[sizeof (EFI_SYSTEM_CONTEXT_IPF) + 512];\r
40\r
41//\r
42// The PatchSaveBuffer is used to store the original bundles from the IVT where it is patched\r
43// with the common handler.\r
44//\r
45UINT8 PatchSaveBuffer[0x400];\r
46UINTN ExternalInterruptCount;\r
47\r
c1f23d63 48\r
9e604fe4 49/**\r
50 IPF specific DebugSupport driver initialization. \r
c1f23d63 51\r
9e604fe4 52 Must be public because it's referenced from DebugSupport.c\r
c1f23d63 53\r
9e604fe4 54 @retval EFI_SUCCESS Always.\r
c1f23d63 55\r
9e604fe4 56**/\r
57EFI_STATUS\r
58PlInitializeDebugSupportDriver (\r
59 VOID\r
60 )\r
c1f23d63 61{\r
519f076a 62 ZeroMem (IvtEntryTable, sizeof (IvtEntryTable));\r
c1f23d63 63 ExternalInterruptCount = 0;\r
64 return EFI_SUCCESS;\r
65}\r
66\r
9e604fe4 67/**\r
c1f23d63 68 Unload handler that is called during UnloadImage() - deallocates pool memory\r
69 used by the driver. Must be public because it's referenced from DebugSuport.c\r
70\r
9e604fe4 71 @param ImageHandle The firmware allocated handle for the EFI image.\r
c1f23d63 72\r
9e604fe4 73 @retval EFI_SUCCESS Always.\r
c1f23d63 74\r
9e604fe4 75**/\r
76EFI_STATUS\r
77EFIAPI\r
78PlUnloadDebugSupportDriver (\r
79 IN EFI_HANDLE ImageHandle\r
80 )\r
c1f23d63 81{\r
82 EFI_EXCEPTION_TYPE ExceptionType;\r
83\r
84 for (ExceptionType = 0; ExceptionType < NUM_IVT_ENTRIES; ExceptionType++) {\r
85 ManageIvtEntryTable (ExceptionType, NULL, NULL);\r
86 }\r
87\r
88 return EFI_SUCCESS;\r
89}\r
90\r
9e604fe4 91/**\r
92 C routine that is called for all registered exceptions. This is the main\r
93 exception dispatcher. Must be public because it's referenced from AsmFuncs.s.\r
94\r
95 @param ExceptionType Exception Type\r
96 @param Context System Context\r
97**/\r
c1f23d63 98VOID\r
99CommonHandler (\r
100 IN EFI_EXCEPTION_TYPE ExceptionType,\r
101 IN EFI_SYSTEM_CONTEXT Context\r
102 )\r
c1f23d63 103{\r
c1f23d63 104 DEBUG_CODE_BEGIN ();\r
19b15d63 105 if (mInHandler) {\r
c1f23d63 106 DEBUG ((EFI_D_INFO, "ERROR: Re-entered debugger!\n"\r
107 " ExceptionType == %X\n"\r
108 " Context == %X\n"\r
109 " Context.SystemContextIpf->CrIip == %X\n"\r
110 " Context.SystemContextIpf->CrIpsr == %X\n"\r
19b15d63 111 " mInHandler == %X\n",\r
c1f23d63 112 ExceptionType, \r
113 Context, \r
114 Context.SystemContextIpf->CrIip,\r
115 Context.SystemContextIpf->CrIpsr,\r
19b15d63 116 mInHandler));\r
c1f23d63 117 }\r
118 DEBUG_CODE_END ();\r
119\r
19b15d63 120 ASSERT (!mInHandler);\r
121 mInHandler = TRUE;\r
c1f23d63 122 if (IvtEntryTable[ExceptionType].RegisteredCallback != NULL) {\r
123 if (ExceptionType != EXCEPT_IPF_EXTERNAL_INTERRUPT) {\r
124 IvtEntryTable[ExceptionType].RegisteredCallback (ExceptionType, Context.SystemContextIpf);\r
125 } else {\r
126 IvtEntryTable[ExceptionType].RegisteredCallback (Context.SystemContextIpf);\r
127 }\r
128 } else {\r
129 ASSERT (0);\r
130 }\r
131\r
19b15d63 132 mInHandler = FALSE;\r
c1f23d63 133}\r
134\r
9e604fe4 135/**\r
136 Given an integer number, return the physical address of the entry point in the IFT.\r
137\r
138 @param HandlerIndex Index of the Handler \r
139 @param EntryPoint IFT Entrypoint\r
140\r
141**/\r
c1f23d63 142VOID\r
143GetHandlerEntryPoint (\r
144 UINTN HandlerIndex,\r
145 VOID **EntryPoint\r
146 )\r
c1f23d63 147{\r
148 UINT8 *TempPtr;\r
149\r
150 //\r
151 // get base address of IVT\r
152 //\r
153 TempPtr = GetIva ();\r
154\r
155 if (HandlerIndex < 20) {\r
156 //\r
157 // first 20 provide 64 bundles per vector\r
158 //\r
159 TempPtr += 0x400 * HandlerIndex;\r
160 } else {\r
161 //\r
162 // the rest provide 16 bundles per vector\r
163 //\r
164 TempPtr += 0x5000 + 0x100 * (HandlerIndex - 20);\r
165 }\r
166\r
167 *EntryPoint = (VOID *) TempPtr;\r
168}\r
169\r
9e604fe4 170/**\r
171 This is the worker function that uninstalls and removes all handlers.\r
172\r
173 @param ExceptionType Exception Type\r
174 @param NewBundles New Boundles\r
175 @param NewCallback New Callback\r
176\r
177 @retval EFI_ALEADY_STARTED Ivt already hooked.\r
178 @retval others Indicates the request was not satisfied.\r
179 @retval EFI_SUCCESS Successfully uninstalled.\r
180\r
181**/\r
c1f23d63 182EFI_STATUS\r
183ManageIvtEntryTable (\r
9e604fe4 184 IN EFI_EXCEPTION_TYPE ExceptionType,\r
c1f23d63 185 IN BUNDLE NewBundles[NUM_BUNDLES_IN_STUB],\r
186 IN VOID (*NewCallback) ()\r
187 )\r
c1f23d63 188{\r
189 BUNDLE *B0Ptr;\r
190 UINT64 InterruptFlags;\r
191 EFI_TPL OldTpl;\r
192\r
193 //\r
194 // Get address of bundle 0\r
195 //\r
196 GetHandlerEntryPoint (ExceptionType, (VOID **) &B0Ptr);\r
197\r
198 if (IvtEntryTable[ExceptionType].RegisteredCallback != NULL) {\r
199 //\r
200 // we've already installed to this vector\r
201 //\r
202 if (NewCallback != NULL) {\r
203 //\r
204 // if the input handler is non-null, error\r
205 //\r
206 return EFI_ALREADY_STARTED;\r
207 } else {\r
208 //\r
209 // else remove the previously installed handler\r
210 //\r
211 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
212 InterruptFlags = ProgramInterruptFlags (DISABLE_INTERRUPTS);\r
213 if (ExceptionType == EXCEPT_IPF_EXTERNAL_INTERRUPT) {\r
214 UnchainExternalInterrupt ();\r
215 } else {\r
216 UnhookEntry (ExceptionType);\r
217 }\r
218\r
219 ProgramInterruptFlags (InterruptFlags);\r
220 gBS->RestoreTPL (OldTpl);\r
221 //\r
222 // re-init IvtEntryTable\r
223 //\r
519f076a 224 ZeroMem (&IvtEntryTable[ExceptionType], sizeof (IVT_ENTRY));\r
c1f23d63 225 }\r
226 } else {\r
227 //\r
228 // no user handler installed on this vector\r
229 //\r
230 if (NewCallback != NULL) {\r
231 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
232 InterruptFlags = ProgramInterruptFlags (DISABLE_INTERRUPTS);\r
233 if (ExceptionType == EXCEPT_IPF_EXTERNAL_INTERRUPT) {\r
234 ChainExternalInterrupt (NewCallback);\r
235 } else {\r
236 HookEntry (ExceptionType, NewBundles, NewCallback);\r
237 }\r
238\r
239 ProgramInterruptFlags (InterruptFlags);\r
240 gBS->RestoreTPL (OldTpl);\r
241 }\r
242 }\r
243\r
244 return EFI_SUCCESS;\r
245}\r
246\r
9e604fe4 247/**\r
248 Saves original IVT contents and inserts a few new bundles which are fixed up\r
249 to store the ExceptionType and then call the common handler.\r
250\r
251 @param ExceptionType Exception Type\r
252 @param NewBundles New Boundles\r
253 @param NewCallback New Callback\r
254\r
255**/\r
c1f23d63 256VOID\r
257HookEntry (\r
258 IN EFI_EXCEPTION_TYPE ExceptionType,\r
259 IN BUNDLE NewBundles[4],\r
260 IN VOID (*NewCallback) ()\r
261 )\r
c1f23d63 262{\r
263 BUNDLE *FixupBundle;\r
264 BUNDLE *B0Ptr;\r
265\r
266 //\r
267 // Get address of bundle 0\r
268 //\r
269 GetHandlerEntryPoint (ExceptionType, (VOID **) &B0Ptr);\r
270\r
271 //\r
272 // copy original bundles from IVT to IvtEntryTable so we can restore them later\r
273 //\r
274 CopyMem (\r
275 IvtEntryTable[ExceptionType].OrigBundles,\r
276 B0Ptr,\r
277 sizeof (BUNDLE) * NUM_BUNDLES_IN_STUB\r
278 );\r
279 //\r
280 // insert new B0\r
281 //\r
282 CopyMem (B0Ptr, NewBundles, sizeof (BUNDLE) * NUM_BUNDLES_IN_STUB);\r
283\r
284 //\r
285 // fixup IVT entry so it stores its index and whether or not to chain...\r
286 //\r
287 FixupBundle = B0Ptr + 2;\r
288 FixupBundle->high |= ExceptionType << 36;\r
289\r
290 InstructionCacheFlush (B0Ptr, 5);\r
291 IvtEntryTable[ExceptionType].RegisteredCallback = NewCallback;\r
292}\r
293\r
9e604fe4 294/**\r
295 Restores original IVT contents when unregistering a callback function.\r
296\r
297 @param ExceptionType Exception Type\r
298\r
299**/\r
c1f23d63 300VOID\r
301UnhookEntry (\r
302 IN EFI_EXCEPTION_TYPE ExceptionType\r
303 )\r
c1f23d63 304{\r
305 BUNDLE *B0Ptr;\r
306\r
307 //\r
308 // Get address of bundle 0\r
309 //\r
310 GetHandlerEntryPoint (ExceptionType, (VOID **) &B0Ptr);\r
311 //\r
312 // restore original bundles in IVT\r
313 //\r
314 CopyMem (\r
315 B0Ptr,\r
316 IvtEntryTable[ExceptionType].OrigBundles,\r
317 sizeof (BUNDLE) * NUM_BUNDLES_IN_STUB\r
318 );\r
319 InstructionCacheFlush (B0Ptr, 5);\r
320}\r
321\r
9e604fe4 322/**\r
c1f23d63 323 Sets up cache flush and calls assembly function to chain external interrupt.\r
9e604fe4 324\r
c1f23d63 325 Records new callback in IvtEntryTable.\r
c1f23d63 326\r
9e604fe4 327 @param NewCallback New Callback\r
c1f23d63 328\r
9e604fe4 329**/\r
330VOID\r
331ChainExternalInterrupt (\r
332 IN VOID (*NewCallback) ()\r
333 )\r
c1f23d63 334{\r
335 VOID *Start;\r
336\r
337 Start = (VOID *) ((UINT8 *) GetIva () + 0x400 * EXCEPT_IPF_EXTERNAL_INTERRUPT + 0x400);\r
338 IvtEntryTable[EXCEPT_IPF_EXTERNAL_INTERRUPT].RegisteredCallback = NewCallback;\r
339 ChainHandler ();\r
340 InstructionCacheFlush (Start, 0x400);\r
341}\r
342\r
9e604fe4 343/**\r
344 Sets up cache flush and calls assembly function to restore external interrupt.\r
345 Removes registered callback from IvtEntryTable.\r
346\r
347**/\r
c1f23d63 348VOID\r
349UnchainExternalInterrupt (\r
350 VOID\r
351 )\r
c1f23d63 352{\r
353 VOID *Start;\r
354\r
355 Start = (VOID *) ((UINT8 *) GetIva () + 0x400 * EXCEPT_IPF_EXTERNAL_INTERRUPT + 0x400);\r
356 UnchainHandler ();\r
357 InstructionCacheFlush (Start, 0x400);\r
358 IvtEntryTable[EXCEPT_IPF_EXTERNAL_INTERRUPT].RegisteredCallback = NULL;\r
359}\r
360\r
361//\r
362// The rest of the functions in this file are all member functions for the\r
363// DebugSupport protocol\r
364//\r
365\r
9e604fe4 366/**\r
367 This is a DebugSupport protocol member function, hard\r
368 coded to support only 1 processor for now.\r
369\r
370 @param This The DebugSupport instance\r
371 @param MaxProcessorIndex The maximuim supported processor index\r
372\r
373 @retval EFI_SUCCESS Always returned with **MaxProcessorIndex set to 0.\r
374\r
375**/\r
c1f23d63 376EFI_STATUS\r
377EFIAPI\r
378GetMaximumProcessorIndex (\r
379 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
380 OUT UINTN *MaxProcessorIndex\r
381 )\r
c1f23d63 382{\r
383 *MaxProcessorIndex = 0;\r
384 return (EFI_SUCCESS);\r
385}\r
386\r
9e604fe4 387/**\r
388 DebugSupport protocol member function.\r
389\r
390 @param This The DebugSupport instance\r
391 @param ProcessorIndex Which processor the callback applies to.\r
392 @param PeriodicCallback Callback function\r
393\r
394 @retval EFI_SUCCESS Indicates the callback was registered.\r
395 @retval others Callback was not registered.\r
396\r
397**/\r
c1f23d63 398EFI_STATUS\r
399EFIAPI\r
400RegisterPeriodicCallback (\r
401 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
402 IN UINTN ProcessorIndex,\r
9e604fe4 403 IN EFI_PERIODIC_CALLBACK PeriodicCallback\r
c1f23d63 404 )\r
9e604fe4 405{\r
406 return ManageIvtEntryTable (EXCEPT_IPF_EXTERNAL_INTERRUPT, NULL, PeriodicCallback);\r
407}\r
c1f23d63 408\r
9e604fe4 409/**\r
410 DebugSupport protocol member function.\r
c1f23d63 411\r
9e604fe4 412 @param This The DebugSupport instance\r
413 @param ProcessorIndex Which processor the callback applies to.\r
414 @param NewCallback Callback function\r
415 @param ExceptionType Which exception to hook\r
c1f23d63 416\r
9e604fe4 417 @retval EFI_SUCCESS Indicates the callback was registered.\r
418 @retval others Callback was not registered.\r
c1f23d63 419\r
9e604fe4 420**/\r
c1f23d63 421EFI_STATUS\r
422EFIAPI\r
423RegisterExceptionCallback (\r
424 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
425 IN UINTN ProcessorIndex,\r
426 IN EFI_EXCEPTION_CALLBACK NewCallback,\r
427 IN EFI_EXCEPTION_TYPE ExceptionType\r
428 )\r
c1f23d63 429{\r
430 return ManageIvtEntryTable (\r
431 ExceptionType,\r
432 (BUNDLE *) ((EFI_PLABEL *) HookStub)->EntryPoint,\r
433 NewCallback\r
434 );\r
435}\r
436\r
9e604fe4 437/**\r
438 DebugSupport protocol member function. Calls assembly routine to flush cache.\r
439\r
440 @param This The DebugSupport instance\r
441 @param ProcessorIndex Which processor the callback applies to.\r
442 @param Start Physical base of the memory range to be invalidated\r
443 @param Length mininum number of bytes in instruction cache to invalidate\r
444\r
445 @retval EFI_SUCCESS Always returned.\r
446\r
447**/\r
c1f23d63 448EFI_STATUS\r
449EFIAPI\r
450InvalidateInstructionCache (\r
451 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
452 IN UINTN ProcessorIndex,\r
453 IN VOID *Start,\r
454 IN UINTN Length\r
455 )\r
c1f23d63 456{\r
457 InstructionCacheFlush (Start, Length);\r
9e604fe4 458 return EFI_SUCCESS;\r
c1f23d63 459}\r