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