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