]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Universal/DebugSupport/Dxe/ipf/plDebugSupport.c
6f2ded213ea7855da82e5928f54abbd40e16ce77
[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 (
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 )
209 ASSERT (!InHandler);
210 InHandler = TRUE;
211 if (IvtEntryTable[ExceptionType].RegisteredCallback != NULL) {
212 if (ExceptionType != EXCEPT_IPF_EXTERNAL_INTERRUPT) {
213 IvtEntryTable[ExceptionType].RegisteredCallback (ExceptionType, Context.SystemContextIpf);
214 } else {
215 IvtEntryTable[ExceptionType].RegisteredCallback (Context.SystemContextIpf);
216 }
217 } else {
218 ASSERT (0);
219 }
220
221 InHandler = FALSE;
222 }
223
224 STATIC
225 VOID
226 GetHandlerEntryPoint (
227 UINTN HandlerIndex,
228 VOID **EntryPoint
229 )
230 /*++
231
232 Routine Description:
233 Given an integer number, return the physical address of the entry point in the IFT
234
235 Arguments:
236 UINTN HandlerIndex,
237 VOID ** EntryPoint
238
239 Returns:
240
241 Nothing
242
243 --*/
244 // TODO: HandlerIndex - add argument and description to function comment
245 // TODO: EntryPoint - add argument and description to function comment
246 {
247 UINT8 *TempPtr;
248
249 //
250 // get base address of IVT
251 //
252 TempPtr = GetIva ();
253
254 if (HandlerIndex < 20) {
255 //
256 // first 20 provide 64 bundles per vector
257 //
258 TempPtr += 0x400 * HandlerIndex;
259 } else {
260 //
261 // the rest provide 16 bundles per vector
262 //
263 TempPtr += 0x5000 + 0x100 * (HandlerIndex - 20);
264 }
265
266 *EntryPoint = (VOID *) TempPtr;
267 }
268
269 STATIC
270 EFI_STATUS
271 ManageIvtEntryTable (
272 IN EFI_EXCEPTION_TYPE ExceptionType,
273 IN BUNDLE NewBundles[NUM_BUNDLES_IN_STUB],
274 IN VOID (*NewCallback) ()
275 )
276 /*++
277
278 Routine Description:
279 This is the worker function that installs and removes all handlers
280
281 Arguments:
282 IN EFI_EXCEPTION_TYPE ExceptionType,
283 IN BUNDLE NewBundles[NUM_BUNDLES_IN_STUB],
284 IN VOID (*NewCallback) ()
285
286 Returns:
287
288 EFI_STATUS - any return other than EFI_SUCCESS indicates the request was not
289 satisfied.
290
291 --*/
292 // TODO: ExceptionType - add argument and description to function comment
293 // TODO: ] - add argument and description to function comment
294 // TODO: ) - add argument and description to function comment
295 // TODO: EFI_ALREADY_STARTED - add return value to function comment
296 {
297 BUNDLE *B0Ptr;
298 UINT64 InterruptFlags;
299 EFI_TPL OldTpl;
300
301 //
302 // Get address of bundle 0
303 //
304 GetHandlerEntryPoint (ExceptionType, (VOID **) &B0Ptr);
305
306 if (IvtEntryTable[ExceptionType].RegisteredCallback != NULL) {
307 //
308 // we've already installed to this vector
309 //
310 if (NewCallback != NULL) {
311 //
312 // if the input handler is non-null, error
313 //
314 return EFI_ALREADY_STARTED;
315 } else {
316 //
317 // else remove the previously installed handler
318 //
319 OldTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL);
320 InterruptFlags = ProgramInterruptFlags (DISABLE_INTERRUPTS);
321 if (ExceptionType == EXCEPT_IPF_EXTERNAL_INTERRUPT) {
322 UnchainExternalInterrupt ();
323 } else {
324 UnhookEntry (ExceptionType);
325 }
326
327 ProgramInterruptFlags (InterruptFlags);
328 gBS->RestoreTPL (OldTpl);
329 //
330 // re-init IvtEntryTable
331 //
332 gBS->SetMem (&IvtEntryTable[ExceptionType], sizeof (IVT_ENTRY), 0);
333 }
334 } else {
335 //
336 // no user handler installed on this vector
337 //
338 if (NewCallback != NULL) {
339 OldTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL);
340 InterruptFlags = ProgramInterruptFlags (DISABLE_INTERRUPTS);
341 if (ExceptionType == EXCEPT_IPF_EXTERNAL_INTERRUPT) {
342 ChainExternalInterrupt (NewCallback);
343 } else {
344 HookEntry (ExceptionType, NewBundles, NewCallback);
345 }
346
347 ProgramInterruptFlags (InterruptFlags);
348 gBS->RestoreTPL (OldTpl);
349 }
350 }
351
352 return EFI_SUCCESS;
353 }
354
355 STATIC
356 VOID
357 HookEntry (
358 IN EFI_EXCEPTION_TYPE ExceptionType,
359 IN BUNDLE NewBundles[4],
360 IN VOID (*NewCallback) ()
361 )
362 /*++
363
364 Routine Description:
365 Saves original IVT contents and inserts a few new bundles which are fixed up
366 to store the ExceptionType and then call the common handler.
367
368 Arguments:
369 IN EFI_EXCEPTION_TYPE ExceptionType,
370 IN BUNDLE NewBundles[4],
371 IN VOID (*NewCallback) ()
372
373 Returns:
374
375 Nothing
376
377 --*/
378 // TODO: ExceptionType - add argument and description to function comment
379 // TODO: ] - add argument and description to function comment
380 // TODO: ) - add argument and description to function comment
381 {
382 BUNDLE *FixupBundle;
383 BUNDLE *B0Ptr;
384
385 //
386 // Get address of bundle 0
387 //
388 GetHandlerEntryPoint (ExceptionType, (VOID **) &B0Ptr);
389
390 //
391 // copy original bundles from IVT to IvtEntryTable so we can restore them later
392 //
393 gBS->CopyMem (
394 IvtEntryTable[ExceptionType].OrigBundles,
395 B0Ptr,
396 sizeof (BUNDLE) * NUM_BUNDLES_IN_STUB
397 );
398 //
399 // insert new B0
400 //
401 gBS->CopyMem (B0Ptr, NewBundles, sizeof (BUNDLE) * NUM_BUNDLES_IN_STUB);
402
403 //
404 // fixup IVT entry so it stores its index and whether or not to chain...
405 //
406 FixupBundle = B0Ptr + 2;
407 FixupBundle->high |= ExceptionType << 36;
408
409 InstructionCacheFlush (B0Ptr, 5);
410 IvtEntryTable[ExceptionType].RegisteredCallback = NewCallback;
411 }
412
413 STATIC
414 VOID
415 UnhookEntry (
416 IN EFI_EXCEPTION_TYPE ExceptionType
417 )
418 /*++
419
420 Routine Description:
421 Restores original IVT contents when unregistering a callback function
422
423 Arguments:
424 IN EFI_EXCEPTION_TYPE ExceptionType,
425
426 Returns:
427
428 Nothing
429
430 --*/
431 // TODO: ExceptionType - add argument and description to function comment
432 {
433 BUNDLE *B0Ptr;
434
435 //
436 // Get address of bundle 0
437 //
438 GetHandlerEntryPoint (ExceptionType, (VOID **) &B0Ptr);
439 //
440 // restore original bundles in IVT
441 //
442 gBS->CopyMem (
443 B0Ptr,
444 IvtEntryTable[ExceptionType].OrigBundles,
445 sizeof (BUNDLE) * NUM_BUNDLES_IN_STUB
446 );
447 InstructionCacheFlush (B0Ptr, 5);
448 }
449
450 STATIC
451 VOID
452 ChainExternalInterrupt (
453 IN VOID (*NewCallback) ()
454 )
455 /*++
456
457 Routine Description:
458 Sets up cache flush and calls assembly function to chain external interrupt.
459 Records new callback in IvtEntryTable.
460
461 Arguments:
462 IN VOID (*NewCallback) ()
463
464 Returns:
465
466 Nothing
467
468 --*/
469 // TODO: ) - add argument and description to function comment
470 {
471 VOID *Start;
472
473 Start = (VOID *) ((UINT8 *) GetIva () + 0x400 * EXCEPT_IPF_EXTERNAL_INTERRUPT + 0x400);
474 IvtEntryTable[EXCEPT_IPF_EXTERNAL_INTERRUPT].RegisteredCallback = NewCallback;
475 ChainHandler ();
476 InstructionCacheFlush (Start, 0x400);
477 }
478
479 STATIC
480 VOID
481 UnchainExternalInterrupt (
482 VOID
483 )
484 /*++
485
486 Routine Description:
487 Sets up cache flush and calls assembly function to restore external interrupt.
488 Removes registered callback from IvtEntryTable.
489
490 Arguments:
491 Nothing
492
493 Returns:
494
495 Nothing
496
497 --*/
498 {
499 VOID *Start;
500
501 Start = (VOID *) ((UINT8 *) GetIva () + 0x400 * EXCEPT_IPF_EXTERNAL_INTERRUPT + 0x400);
502 UnchainHandler ();
503 InstructionCacheFlush (Start, 0x400);
504 IvtEntryTable[EXCEPT_IPF_EXTERNAL_INTERRUPT].RegisteredCallback = NULL;
505 }
506
507 //
508 // The rest of the functions in this file are all member functions for the
509 // DebugSupport protocol
510 //
511
512 EFI_STATUS
513 EFIAPI
514 GetMaximumProcessorIndex (
515 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
516 OUT UINTN *MaxProcessorIndex
517 )
518 /*++
519
520 Routine Description: This is a DebugSupport protocol member function. Hard
521 coded to support only 1 processor for now.
522
523 Arguments:
524
525 Returns: Always returns EFI_SUCCESS with *MaxProcessorIndex set to 0
526
527 --*/
528 // TODO: This - add argument and description to function comment
529 // TODO: MaxProcessorIndex - add argument and description to function comment
530 {
531 *MaxProcessorIndex = 0;
532 return (EFI_SUCCESS);
533 }
534
535 EFI_STATUS
536 EFIAPI
537 RegisterPeriodicCallback (
538 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
539 IN UINTN ProcessorIndex,
540 IN EFI_PERIODIC_CALLBACK NewPeriodicCallback
541 )
542 /*++
543
544 Routine Description:
545 DebugSupport protocol member function
546
547 Arguments:
548 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
549 IN UINTN ProcessorIndex,
550 IN EFI_PERIODIC_CALLBACK NewPeriodicCallback
551
552 Returns:
553
554 EFI_STATUS - anything other than EFI_SUCCESS indicates the callback was not registered.
555
556 --*/
557 // TODO: This - add argument and description to function comment
558 // TODO: ProcessorIndex - add argument and description to function comment
559 // TODO: NewPeriodicCallback - add argument and description to function comment
560 {
561 return ManageIvtEntryTable (EXCEPT_IPF_EXTERNAL_INTERRUPT, NULL, NewPeriodicCallback);
562 }
563
564 EFI_STATUS
565 EFIAPI
566 RegisterExceptionCallback (
567 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
568 IN UINTN ProcessorIndex,
569 IN EFI_EXCEPTION_CALLBACK NewCallback,
570 IN EFI_EXCEPTION_TYPE ExceptionType
571 )
572 /*++
573
574 Routine Description:
575 DebugSupport protocol member function
576
577 Arguments:
578 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
579 IN EFI_EXCEPTION_CALLBACK NewCallback,
580 IN EFI_EXCEPTION_TYPE ExceptionType
581
582 Returns:
583
584 EFI_STATUS - anything other than EFI_SUCCESS indicates the callback was not registered.
585
586 --*/
587 // TODO: This - add argument and description to function comment
588 // TODO: ProcessorIndex - add argument and description to function comment
589 // TODO: NewCallback - add argument and description to function comment
590 // TODO: ExceptionType - add argument and description to function comment
591 {
592 return ManageIvtEntryTable (
593 ExceptionType,
594 (BUNDLE *) ((EFI_PLABEL *) HookStub)->EntryPoint,
595 NewCallback
596 );
597 }
598
599 EFI_STATUS
600 EFIAPI
601 InvalidateInstructionCache (
602 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
603 IN UINTN ProcessorIndex,
604 IN VOID *Start,
605 IN UINTN Length
606 )
607 /*++
608
609 Routine Description:
610 DebugSupport protocol member function. Calls assembly routine to flush cache.
611
612 Arguments:
613
614 Returns:
615 EFI_SUCCESS
616
617 --*/
618 // TODO: This - add argument and description to function comment
619 // TODO: ProcessorIndex - add argument and description to function comment
620 // TODO: Start - add argument and description to function comment
621 // TODO: Length - add argument and description to function comment
622 {
623 InstructionCacheFlush (Start, Length);
624 return (EFI_SUCCESS);
625 }