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