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