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