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