filename renaming to meet coding style.
[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 EFI_STATUS
39 ManageIvtEntryTable (
40 IN EFI_EXCEPTION_TYPE ExceptionType,
41 IN BUNDLE NewBundles[4],
42 IN VOID (*NewCallback) ()
43 );
44
45 VOID
46 HookEntry (
47 IN EFI_EXCEPTION_TYPE ExceptionType,
48 IN BUNDLE NewBundles[4],
49 IN VOID (*NewCallback) ()
50 );
51
52 VOID
53 UnhookEntry (
54 IN EFI_EXCEPTION_TYPE ExceptionType
55 );
56
57 VOID
58 ChainExternalInterrupt (
59 IN VOID (*NewCallback) ()
60 );
61
62 VOID
63 UnchainExternalInterrupt (
64 VOID
65 );
66
67 VOID
68 GetHandlerEntryPoint (
69 UINTN HandlerIndex,
70 VOID **EntryPoint
71 );
72
73 IVT_ENTRY IvtEntryTable[NUM_IVT_ENTRIES];
74
75 //
76 // IPF context record is overallocated by 512 bytes to guarantee a 512 byte alignment exists
77 // within the buffer and still have a large enough buffer to hold a whole IPF context record.
78 //
79 UINT8 IpfContextBuf[sizeof (EFI_SYSTEM_CONTEXT_IPF) + 512];
80
81 //
82 // The PatchSaveBuffer is used to store the original bundles from the IVT where it is patched
83 // with the common handler.
84 //
85 UINT8 PatchSaveBuffer[0x400];
86 UINTN ExternalInterruptCount;
87
88 EFI_STATUS
89 plInitializeDebugSupportDriver (
90 VOID
91 )
92 /*++
93
94 Routine Description:
95 IPF specific DebugSupport driver initialization. Must be public because it's
96 referenced from DebugSupport.c
97
98 Arguments:
99
100 Returns:
101
102 EFI_SUCCESS
103
104 --*/
105 {
106 SetMem (IvtEntryTable, sizeof (IvtEntryTable), 0);
107 ExternalInterruptCount = 0;
108 return EFI_SUCCESS;
109 }
110
111 EFI_STATUS
112 EFIAPI
113 plUnloadDebugSupportDriver (
114 IN EFI_HANDLE ImageHandle
115 )
116 /*++
117
118 Routine Description:
119 Unload handler that is called during UnloadImage() - deallocates pool memory
120 used by the driver. Must be public because it's referenced from DebugSuport.c
121
122 Arguments:
123 ImageHandle - Image handle
124
125 Returns:
126
127 EFI_STATUS - anything other than EFI_SUCCESS indicates the callback was not registered.
128
129 --*/
130 {
131 EFI_EXCEPTION_TYPE ExceptionType;
132
133 for (ExceptionType = 0; ExceptionType < NUM_IVT_ENTRIES; ExceptionType++) {
134 ManageIvtEntryTable (ExceptionType, NULL, NULL);
135 }
136
137 return EFI_SUCCESS;
138 }
139
140 VOID
141 CommonHandler (
142 IN EFI_EXCEPTION_TYPE ExceptionType,
143 IN EFI_SYSTEM_CONTEXT Context
144 )
145 /*++
146
147 Routine Description:
148 C routine that is called for all registered exceptions. This is the main
149 exception dispatcher. Must be public because it's referenced from AsmFuncs.s.
150
151 Arguments:
152 ExceptionType - Exception Type
153 Context - System Context
154
155 Returns:
156
157 Nothing
158
159 --*/
160 {
161 DEBUG_CODE_BEGIN ();
162 if (mInHandler) {
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 " mInHandler == %X\n",
169 ExceptionType,
170 Context,
171 Context.SystemContextIpf->CrIip,
172 Context.SystemContextIpf->CrIpsr,
173 mInHandler));
174 }
175 DEBUG_CODE_END ();
176
177 ASSERT (!mInHandler);
178 mInHandler = 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 mInHandler = 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 }