]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/DebugSupportDxe/Ipf/PlDebugSupport.c
Update the copyright notice format
[mirror_edk2.git] / MdeModulePkg / Universal / DebugSupportDxe / Ipf / PlDebugSupport.c
CommitLineData
9e604fe4 1/** @file\r
509bc208 2 IPF specific functions to support Debug Support protocol.\r
c1f23d63 3\r
e5eed7d3
HT
4Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
5This program and the accompanying materials\r
ed055f1b 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
c1f23d63 12\r
13**/\r
14\r
e9f9d09a 15#include "PlDebugSupport.h"\r
c1f23d63 16\r
19b15d63 17BOOLEAN mInHandler = FALSE;\r
18\r
c1f23d63 19//\r
20// number of bundles to swap in ivt\r
21//\r
22#define NUM_BUNDLES_IN_STUB 5\r
23#define NUM_IVT_ENTRIES 64\r
24\r
25typedef struct {\r
1ccdbf2a 26 BUNDLE OrigBundles[NUM_BUNDLES_IN_STUB];\r
27 CALLBACK_FUNC RegisteredCallback;\r
c1f23d63 28} IVT_ENTRY;\r
29\r
aa79b0b3 30IVT_ENTRY IvtEntryTable[NUM_IVT_ENTRIES];\r
31\r
32//\r
33// IPF context record is overallocated by 512 bytes to guarantee a 512 byte alignment exists\r
34// within the buffer and still have a large enough buffer to hold a whole IPF context record.\r
35//\r
36UINT8 IpfContextBuf[sizeof (EFI_SYSTEM_CONTEXT_IPF) + 512];\r
37\r
38//\r
39// The PatchSaveBuffer is used to store the original bundles from the IVT where it is patched\r
40// with the common handler.\r
41//\r
42UINT8 PatchSaveBuffer[0x400];\r
43UINTN ExternalInterruptCount;\r
44\r
c1f23d63 45\r
9e604fe4 46/**\r
ed055f1b 47 IPF specific DebugSupport driver initialization.\r
c1f23d63 48\r
9e604fe4 49 Must be public because it's referenced from DebugSupport.c\r
c1f23d63 50\r
9e604fe4 51 @retval EFI_SUCCESS Always.\r
c1f23d63 52\r
9e604fe4 53**/\r
54EFI_STATUS\r
55PlInitializeDebugSupportDriver (\r
56 VOID\r
57 )\r
c1f23d63 58{\r
519f076a 59 ZeroMem (IvtEntryTable, sizeof (IvtEntryTable));\r
c1f23d63 60 ExternalInterruptCount = 0;\r
61 return EFI_SUCCESS;\r
62}\r
63\r
9e604fe4 64/**\r
c1f23d63 65 Unload handler that is called during UnloadImage() - deallocates pool memory\r
ed055f1b 66 used by the driver.\r
509bc208 67\r
68 Must be public because it's referenced from DebugSuport.c\r
c1f23d63 69\r
9e604fe4 70 @param ImageHandle The firmware allocated handle for the EFI image.\r
c1f23d63 71\r
9e604fe4 72 @retval EFI_SUCCESS Always.\r
c1f23d63 73\r
9e604fe4 74**/\r
75EFI_STATUS\r
76EFIAPI\r
77PlUnloadDebugSupportDriver (\r
78 IN EFI_HANDLE ImageHandle\r
79 )\r
c1f23d63 80{\r
81 EFI_EXCEPTION_TYPE ExceptionType;\r
82\r
83 for (ExceptionType = 0; ExceptionType < NUM_IVT_ENTRIES; ExceptionType++) {\r
84 ManageIvtEntryTable (ExceptionType, NULL, NULL);\r
85 }\r
86\r
87 return EFI_SUCCESS;\r
88}\r
89\r
9e604fe4 90/**\r
91 C routine that is called for all registered exceptions. This is the main\r
ed055f1b 92 exception dispatcher.\r
509bc208 93\r
94 Must be public because it's referenced from AsmFuncs.s.\r
9e604fe4 95\r
509bc208 96 @param ExceptionType Specifies which processor exception.\r
97 @param Context System Context.\r
9e604fe4 98**/\r
c1f23d63 99VOID\r
100CommonHandler (\r
101 IN EFI_EXCEPTION_TYPE ExceptionType,\r
102 IN EFI_SYSTEM_CONTEXT Context\r
103 )\r
c1f23d63 104{\r
c1f23d63 105 DEBUG_CODE_BEGIN ();\r
19b15d63 106 if (mInHandler) {\r
c1f23d63 107 DEBUG ((EFI_D_INFO, "ERROR: Re-entered debugger!\n"\r
108 " ExceptionType == %X\n"\r
109 " Context == %X\n"\r
7df7393f 110 " Context.SystemContextIpf->CrIip == %LX\n"\r
111 " Context.SystemContextIpf->CrIpsr == %LX\n"\r
19b15d63 112 " mInHandler == %X\n",\r
ed055f1b 113 (INT32)ExceptionType,\r
114 Context,\r
c1f23d63 115 Context.SystemContextIpf->CrIip,\r
116 Context.SystemContextIpf->CrIpsr,\r
19b15d63 117 mInHandler));\r
c1f23d63 118 }\r
119 DEBUG_CODE_END ();\r
120\r
19b15d63 121 ASSERT (!mInHandler);\r
122 mInHandler = TRUE;\r
c1f23d63 123 if (IvtEntryTable[ExceptionType].RegisteredCallback != NULL) {\r
124 if (ExceptionType != EXCEPT_IPF_EXTERNAL_INTERRUPT) {\r
125 IvtEntryTable[ExceptionType].RegisteredCallback (ExceptionType, Context.SystemContextIpf);\r
126 } else {\r
127 IvtEntryTable[ExceptionType].RegisteredCallback (Context.SystemContextIpf);\r
128 }\r
129 } else {\r
130 ASSERT (0);\r
131 }\r
132\r
19b15d63 133 mInHandler = FALSE;\r
c1f23d63 134}\r
135\r
9e604fe4 136/**\r
137 Given an integer number, return the physical address of the entry point in the IFT.\r
138\r
ed055f1b 139 @param HandlerIndex Index of the Handler\r
9e604fe4 140 @param EntryPoint IFT Entrypoint\r
141\r
142**/\r
c1f23d63 143VOID\r
144GetHandlerEntryPoint (\r
145 UINTN HandlerIndex,\r
146 VOID **EntryPoint\r
147 )\r
c1f23d63 148{\r
149 UINT8 *TempPtr;\r
150\r
151 //\r
152 // get base address of IVT\r
153 //\r
154 TempPtr = GetIva ();\r
155\r
156 if (HandlerIndex < 20) {\r
157 //\r
158 // first 20 provide 64 bundles per vector\r
159 //\r
160 TempPtr += 0x400 * HandlerIndex;\r
161 } else {\r
162 //\r
163 // the rest provide 16 bundles per vector\r
164 //\r
165 TempPtr += 0x5000 + 0x100 * (HandlerIndex - 20);\r
166 }\r
167\r
168 *EntryPoint = (VOID *) TempPtr;\r
169}\r
170\r
9e604fe4 171/**\r
172 This is the worker function that uninstalls and removes all handlers.\r
173\r
509bc208 174 @param ExceptionType Specifies which processor exception.\r
175 @param NewBundles New Boundles.\r
176 @param NewCallback A pointer to the new function to be registered.\r
9e604fe4 177\r
178 @retval EFI_ALEADY_STARTED Ivt already hooked.\r
9e604fe4 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
1ccdbf2a 186 IN CALLBACK_FUNC NewCallback\r
c1f23d63 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
509bc208 251 @param ExceptionType Specifies which processor exception.\r
252 @param NewBundles New Boundles.\r
253 @param NewCallback A pointer to the new function to be hooked.\r
9e604fe4 254\r
255**/\r
c1f23d63 256VOID\r
257HookEntry (\r
258 IN EFI_EXCEPTION_TYPE ExceptionType,\r
259 IN BUNDLE NewBundles[4],\r
1ccdbf2a 260 IN CALLBACK_FUNC NewCallback\r
c1f23d63 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
1ccdbf2a 288 FixupBundle->High |= ExceptionType << 36;\r
c1f23d63 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
509bc208 297 @param ExceptionType Specifies which processor exception.\r
9e604fe4 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
509bc208 327 @param NewCallback A pointer to the interrupt handle.\r
c1f23d63 328\r
9e604fe4 329**/\r
330VOID\r
331ChainExternalInterrupt (\r
1ccdbf2a 332 IN CALLBACK_FUNC NewCallback\r
9e604fe4 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
9e604fe4 361/**\r
509bc208 362 Returns the maximum value that may be used for the ProcessorIndex parameter in\r
ed055f1b 363 RegisterPeriodicCallback() and RegisterExceptionCallback().\r
364\r
509bc208 365 Hard coded to support only 1 processor for now.\r
9e604fe4 366\r
509bc208 367 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.\r
368 @param MaxProcessorIndex Pointer to a caller-allocated UINTN in which the maximum supported\r
ed055f1b 369 processor index is returned. Always 0 returned.\r
370\r
509bc208 371 @retval EFI_SUCCESS Always returned with **MaxProcessorIndex set to 0.\r
9e604fe4 372\r
373**/\r
c1f23d63 374EFI_STATUS\r
375EFIAPI\r
376GetMaximumProcessorIndex (\r
377 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
378 OUT UINTN *MaxProcessorIndex\r
379 )\r
c1f23d63 380{\r
381 *MaxProcessorIndex = 0;\r
382 return (EFI_SUCCESS);\r
383}\r
384\r
9e604fe4 385/**\r
509bc208 386 Registers a function to be called back periodically in interrupt context.\r
ed055f1b 387\r
509bc208 388 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.\r
389 @param ProcessorIndex Specifies which processor the callback function applies to.\r
390 @param PeriodicCallback A pointer to a function of type PERIODIC_CALLBACK that is the main\r
391 periodic entry point of the debug agent.\r
ed055f1b 392\r
393 @retval EFI_SUCCESS The function completed successfully.\r
509bc208 394 @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a callback\r
ed055f1b 395 function was previously registered.\r
396 @retval EFI_OUT_OF_RESOURCES System has insufficient memory resources to register new callback\r
397 function.\r
9e604fe4 398**/\r
c1f23d63 399EFI_STATUS\r
400EFIAPI\r
401RegisterPeriodicCallback (\r
402 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
403 IN UINTN ProcessorIndex,\r
9e604fe4 404 IN EFI_PERIODIC_CALLBACK PeriodicCallback\r
c1f23d63 405 )\r
9e604fe4 406{\r
407 return ManageIvtEntryTable (EXCEPT_IPF_EXTERNAL_INTERRUPT, NULL, PeriodicCallback);\r
408}\r
c1f23d63 409\r
9e604fe4 410/**\r
509bc208 411 Registers a function to be called when a given processor exception occurs.\r
412\r
413 This code executes in boot services context.\r
ed055f1b 414\r
509bc208 415 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.\r
416 @param ProcessorIndex Specifies which processor the callback function applies to.\r
417 @param ExceptionCallback A pointer to a function of type EXCEPTION_CALLBACK that is called\r
ed055f1b 418 when the processor exception specified by ExceptionType occurs.\r
419 @param ExceptionType Specifies which processor exception to hook.\r
420\r
421 @retval EFI_SUCCESS The function completed successfully.\r
509bc208 422 @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a callback\r
ed055f1b 423 function was previously registered.\r
424 @retval EFI_OUT_OF_RESOURCES System has insufficient memory resources to register new callback\r
509bc208 425 function.\r
9e604fe4 426**/\r
c1f23d63 427EFI_STATUS\r
428EFIAPI\r
429RegisterExceptionCallback (\r
430 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
431 IN UINTN ProcessorIndex,\r
ed055f1b 432 IN EFI_EXCEPTION_CALLBACK ExceptionCallback,\r
c1f23d63 433 IN EFI_EXCEPTION_TYPE ExceptionType\r
434 )\r
c1f23d63 435{\r
436 return ManageIvtEntryTable (\r
437 ExceptionType,\r
438 (BUNDLE *) ((EFI_PLABEL *) HookStub)->EntryPoint,\r
ed055f1b 439 ExceptionCallback\r
c1f23d63 440 );\r
441}\r
442\r
9e604fe4 443/**\r
509bc208 444 Invalidates processor instruction cache for a memory range. Subsequent execution in this range\r
ed055f1b 445 causes a fresh memory fetch to retrieve code to be executed.\r
446\r
509bc208 447 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.\r
448 @param ProcessorIndex Specifies which processor's instruction cache is to be invalidated.\r
ed055f1b 449 @param Start Specifies the physical base of the memory range to be invalidated.\r
509bc208 450 @param Length Specifies the minimum number of bytes in the processor's instruction\r
ed055f1b 451 cache to invalidate.\r
452\r
509bc208 453 @retval EFI_SUCCESS Always returned.\r
9e604fe4 454\r
455**/\r
c1f23d63 456EFI_STATUS\r
457EFIAPI\r
458InvalidateInstructionCache (\r
459 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
460 IN UINTN ProcessorIndex,\r
461 IN VOID *Start,\r
462 IN UINTN Length\r
463 )\r
c1f23d63 464{\r
465 InstructionCacheFlush (Start, Length);\r
9e604fe4 466 return EFI_SUCCESS;\r
c1f23d63 467}\r