]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - EdkModulePkg/Universal/DebugSupport/Dxe/Ia32/plDebugSupport.c
Perfect the msa of the following modules, DiskIo, Partition, English and Ebc.
[mirror_edk2.git] / EdkModulePkg / Universal / DebugSupport / Dxe / Ia32 / plDebugSupport.c
... / ...
CommitLineData
1/**@file\r
2 IA32 specific debug support functions\r
3 \r
4Copyright (c) 2006 Intel Corporation \r
5All rights reserved. This program and the accompanying materials \r
6are licensed and made available under the terms and conditions of the BSD License \r
7which accompanies this distribution. The full text of the license may be found at \r
8http://opensource.org/licenses/bsd-license.php \r
9 \r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
12\r
13**/\r
14\r
15//\r
16// private header files\r
17//\r
18#include "plDebugSupport.h"\r
19\r
20//\r
21// This the global main table to keep track of the interrupts\r
22//\r
23IDT_ENTRY *IdtEntryTable = NULL;\r
24DESCRIPTOR NullDesc = 0;\r
25\r
26#ifndef EFI_NT_EMULATOR\r
27STATIC\r
28EFI_STATUS\r
29CreateEntryStub (\r
30 IN EFI_EXCEPTION_TYPE ExceptionType,\r
31 OUT VOID **Stub\r
32 )\r
33/*++\r
34\r
35Routine Description: Allocate pool for a new IDT entry stub. Copy the generic\r
36 stub into the new buffer and fixup the vector number and jump target address.\r
37\r
38Arguments:\r
39 ExceptionType - This is the exception type that the new stub will be created\r
40 for.\r
41 Stub - On successful exit, *Stub contains the newly allocated entry stub.\r
42Returns:\r
43 Typically EFI_SUCCESS\r
44 other possibilities are passed through from AllocatePool\r
45\r
46--*/\r
47{\r
48 UINT8 *StubCopy;\r
49\r
50 //\r
51 // First, allocate a new buffer and copy the stub code into it\r
52 //\r
53 *Stub = AllocatePool (StubSize);\r
54 if (*Stub != NULL) {\r
55 StubCopy = *Stub;\r
56 CopyMem (StubCopy, InterruptEntryStub, StubSize);\r
57\r
58 //\r
59 // Next fixup the stub code for this vector\r
60 //\r
61\r
62 // The stub code looks like this:\r
63 //\r
64 // 00000000 89 25 00000004 R mov AppEsp, esp ; save stack top\r
65 // 00000006 BC 00008014 R mov esp, offset DbgStkBot ; switch to debugger stack\r
66 // 0000000B 6A 00 push 0 ; push vector number - will be modified before installed\r
67 // 0000000D E9 db 0e9h ; jump rel32\r
68 // 0000000E 00000000 dd 0 ; fixed up to relative address of CommonIdtEntry\r
69 //\r
70\r
71 //\r
72 // poke in the exception type so the second push pushes the exception type\r
73 //\r
74 StubCopy[0x0c] = (UINT8) ExceptionType;\r
75\r
76 //\r
77 // fixup the jump target to point to the common entry\r
78 //\r
79 *(UINT32 *) &StubCopy[0x0e] = (UINT32) CommonIdtEntry - (UINT32) &StubCopy[StubSize];\r
80 \r
81 return EFI_SUCCESS;\r
82 }\r
83\r
84 return EFI_OUT_OF_RESOURCES;\r
85}\r
86\r
87STATIC\r
88EFI_STATUS\r
89HookEntry (\r
90 IN EFI_EXCEPTION_TYPE ExceptionType,\r
91 IN VOID (*NewCallback) ()\r
92 )\r
93/*++\r
94\r
95Routine Description:\r
96 Creates a nes entry stub. Then saves the current IDT entry and replaces it\r
97 with an interrupt gate for the new entry point. The IdtEntryTable is updated\r
98 with the new registered function.\r
99\r
100 This code executes in boot services context. The stub entry executes in interrupt\r
101 context.\r
102\r
103Arguments:\r
104 ExceptionType - specifies which vector to hook.\r
105 NewCallback - a pointer to the new function to be registered.\r
106\r
107Returns:\r
108 EFI_SUCCESS\r
109 Other possibilities are passed through by CreateEntryStub\r
110\r
111--*/\r
112{\r
113 BOOLEAN OldIntFlagState;\r
114 EFI_STATUS Status;\r
115\r
116 Status = CreateEntryStub (ExceptionType, (VOID **) &IdtEntryTable[ExceptionType].StubEntry);\r
117 if (Status == EFI_SUCCESS) {\r
118 OldIntFlagState = WriteInterruptFlag (0);\r
119 ReadIdt (ExceptionType, &(IdtEntryTable[ExceptionType].OrigDesc));\r
120\r
121 ((UINT16 *) &IdtEntryTable[ExceptionType].OrigVector)[0] = ((UINT16 *) &IdtEntryTable[ExceptionType].OrigDesc)[0];\r
122 ((UINT16 *) &IdtEntryTable[ExceptionType].OrigVector)[1] = ((UINT16 *) &IdtEntryTable[ExceptionType].OrigDesc)[3];\r
123\r
124 Vect2Desc (&IdtEntryTable[ExceptionType].NewDesc, IdtEntryTable[ExceptionType].StubEntry);\r
125 IdtEntryTable[ExceptionType].RegisteredCallback = NewCallback;\r
126 WriteIdt (ExceptionType, &(IdtEntryTable[ExceptionType].NewDesc));\r
127 WriteInterruptFlag (OldIntFlagState);\r
128 }\r
129\r
130 return Status;\r
131}\r
132\r
133STATIC\r
134EFI_STATUS\r
135UnhookEntry (\r
136 IN EFI_EXCEPTION_TYPE ExceptionType\r
137 )\r
138/*++\r
139\r
140Routine Description:\r
141 Undoes HookEntry. This code executes in boot services context.\r
142\r
143Arguments:\r
144 ExceptionType - specifies which entry to unhook\r
145\r
146Returns:\r
147 EFI_SUCCESS\r
148\r
149--*/\r
150{\r
151 BOOLEAN OldIntFlagState;\r
152\r
153 OldIntFlagState = WriteInterruptFlag (0);\r
154 WriteIdt (ExceptionType, &(IdtEntryTable[ExceptionType].OrigDesc));\r
155 FreePool ((VOID *) (UINTN) IdtEntryTable[ExceptionType].StubEntry);\r
156 ZeroMem (&IdtEntryTable[ExceptionType], sizeof (IDT_ENTRY));\r
157 WriteInterruptFlag (OldIntFlagState);\r
158\r
159 return EFI_SUCCESS;\r
160}\r
161#endif\r
162\r
163EFI_STATUS\r
164ManageIdtEntryTable (\r
165 VOID (*NewCallback)(),\r
166 EFI_EXCEPTION_TYPE ExceptionType\r
167 )\r
168/*++\r
169\r
170Routine Description:\r
171 This is the main worker function that manages the state of the interrupt\r
172 handlers. It both installs and uninstalls interrupt handlers based on the\r
173 value of NewCallback. If NewCallback is NULL, then uninstall is indicated.\r
174 If NewCallback is non-NULL, then install is indicated.\r
175\r
176Arguments:\r
177 NewCallback - If non-NULL, NewCallback specifies the new handler to register.\r
178 If NULL, specifies that the previously registered handler should\r
179 be uninstalled.\r
180 ExceptionType - Indicates which entry to manage\r
181\r
182Returns:\r
183 EFI_SUCCESS\r
184 EFI_INVALID_PARAMETER - requested uninstalling a handler from a vector that has\r
185 no handler registered for it\r
186 EFI_ALREADY_STARTED - requested install to a vector that already has a handler registered.\r
187\r
188 Other possible return values are passed through from UnHookEntry and HookEntry.\r
189\r
190--*/\r
191{\r
192 EFI_STATUS Status;\r
193\r
194 Status = EFI_SUCCESS;\r
195\r
196#ifndef EFI_NT_EMULATOR\r
197 if (CompareDescriptor (&IdtEntryTable[ExceptionType].NewDesc, &NullDesc)) {\r
198 //\r
199 // we've already installed to this vector\r
200 //\r
201 if (NewCallback != NULL) {\r
202 //\r
203 // if the input handler is non-null, error\r
204 //\r
205 Status = EFI_ALREADY_STARTED;\r
206 } else {\r
207 Status = UnhookEntry (ExceptionType);\r
208 }\r
209 } else {\r
210 //\r
211 // no user handler installed on this vector\r
212 //\r
213 if (NewCallback == NULL) {\r
214 //\r
215 // if the input handler is null, error\r
216 //\r
217 Status = EFI_INVALID_PARAMETER;\r
218 } else {\r
219 Status = HookEntry (ExceptionType, NewCallback);\r
220 }\r
221 }\r
222#endif\r
223 return Status;\r
224}\r
225\r
226EFI_STATUS\r
227EFIAPI\r
228GetMaximumProcessorIndex (\r
229 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
230 OUT UINTN *MaxProcessorIndex\r
231 )\r
232/*++\r
233\r
234Routine Description: This is a DebugSupport protocol member function.\r
235\r
236Arguments:\r
237 This - The DebugSupport instance\r
238 MaxProcessorIndex - The maximuim supported processor index\r
239\r
240Returns:\r
241 Always returns EFI_SUCCESS with *MaxProcessorIndex set to 0\r
242\r
243--*/\r
244{\r
245 *MaxProcessorIndex = 0;\r
246 return (EFI_SUCCESS);\r
247}\r
248\r
249EFI_STATUS\r
250EFIAPI\r
251RegisterPeriodicCallback (\r
252 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
253 IN UINTN ProcessorIndex,\r
254 IN EFI_PERIODIC_CALLBACK PeriodicCallback\r
255 )\r
256/*++\r
257\r
258Routine Description: This is a DebugSupport protocol member function.\r
259\r
260Arguments:\r
261 This - The DebugSupport instance\r
262 ProcessorIndex - Which processor the callback applies to.\r
263 PeriodicCallback - Callback function\r
264\r
265Returns:\r
266\r
267 EFI_SUCCESS\r
268 EFI_INVALID_PARAMETER - requested uninstalling a handler from a vector that has\r
269 no handler registered for it\r
270 EFI_ALREADY_STARTED - requested install to a vector that already has a handler registered.\r
271\r
272 Other possible return values are passed through from UnHookEntry and HookEntry.\r
273\r
274--*/\r
275{\r
276 return ManageIdtEntryTable (PeriodicCallback, SYSTEM_TIMER_VECTOR);\r
277}\r
278\r
279EFI_STATUS\r
280EFIAPI\r
281RegisterExceptionCallback (\r
282 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
283 IN UINTN ProcessorIndex,\r
284 IN EFI_EXCEPTION_CALLBACK NewCallback,\r
285 IN EFI_EXCEPTION_TYPE ExceptionType\r
286 )\r
287/*++\r
288\r
289Routine Description:\r
290 This is a DebugSupport protocol member function.\r
291\r
292 This code executes in boot services context.\r
293\r
294Arguments:\r
295 This - The DebugSupport instance\r
296 ProcessorIndex - Which processor the callback applies to.\r
297 NewCallback - Callback function\r
298 ExceptionType - Which exception to hook\r
299\r
300Returns:\r
301\r
302 EFI_SUCCESS\r
303 EFI_INVALID_PARAMETER - requested uninstalling a handler from a vector that has\r
304 no handler registered for it\r
305 EFI_ALREADY_STARTED - requested install to a vector that already has a handler registered.\r
306\r
307 Other possible return values are passed through from UnHookEntry and HookEntry.\r
308\r
309--*/\r
310{\r
311 return ManageIdtEntryTable (NewCallback, ExceptionType);\r
312}\r
313\r
314EFI_STATUS\r
315EFIAPI\r
316InvalidateInstructionCache (\r
317 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
318 IN UINTN ProcessorIndex,\r
319 IN VOID *Start,\r
320 IN UINT64 Length\r
321 )\r
322/*++\r
323\r
324Routine Description:\r
325 This is a DebugSupport protocol member function.\r
326 Calls assembly routine to flush cache.\r
327\r
328Arguments:\r
329 This - The DebugSupport instance\r
330 ProcessorIndex - Which processor the callback applies to.\r
331 Start - Physical base of the memory range to be invalidated\r
332 Length - mininum number of bytes in instruction cache to invalidate\r
333\r
334Returns:\r
335\r
336 EFI_SUCCESS - always return success\r
337\r
338--*/\r
339{\r
340 AsmWbinvd ();\r
341 return EFI_SUCCESS;\r
342}\r
343\r
344EFI_STATUS\r
345plInitializeDebugSupportDriver (\r
346 VOID\r
347 )\r
348/*++\r
349\r
350Routine Description:\r
351 Initializes driver's handler registration database.\r
352\r
353 This code executes in boot services context.\r
354\r
355Arguments:\r
356 None\r
357\r
358Returns:\r
359 EFI_SUCCESS\r
360 EFI_UNSUPPORTED - if IA32 processor does not support FXSTOR/FXRSTOR instructions,\r
361 the context save will fail, so these processor's are not supported.\r
362 EFI_OUT_OF_RESOURCES - not resource to finish initialization\r
363\r
364--*/\r
365{\r
366 if (!FxStorSupport ()) {\r
367 return EFI_UNSUPPORTED;\r
368 } else {\r
369 IdtEntryTable = AllocateZeroPool (sizeof (IDT_ENTRY) * NUM_IDT_ENTRIES);\r
370 if (IdtEntryTable != NULL) {\r
371 return EFI_SUCCESS;\r
372 } else {\r
373 return EFI_OUT_OF_RESOURCES;\r
374 }\r
375 }\r
376}\r
377\r
378EFI_STATUS\r
379EFIAPI\r
380plUnloadDebugSupportDriver (\r
381 IN EFI_HANDLE ImageHandle\r
382 )\r
383/*++\r
384\r
385Routine Description:\r
386 This is the callback that is written to the LoadedImage protocol instance\r
387 on the image handle. It uninstalls all registered handlers and frees all entry\r
388 stub memory.\r
389\r
390 This code executes in boot services context.\r
391\r
392Arguments:\r
393 ImageHandle - The image handle of the unload handler\r
394\r
395Returns:\r
396\r
397 EFI_SUCCESS - always return success\r
398\r
399--*/\r
400{\r
401 EFI_EXCEPTION_TYPE ExceptionType;\r
402\r
403 for (ExceptionType = 0; ExceptionType < NUM_IDT_ENTRIES; ExceptionType++) {\r
404 ManageIdtEntryTable (NULL, ExceptionType);\r
405 }\r
406\r
407 FreePool (IdtEntryTable);\r
408 return EFI_SUCCESS;\r
409}\r
410\r
411VOID\r
412InterruptDistrubutionHub (\r
413 EFI_EXCEPTION_TYPE ExceptionType,\r
414 EFI_SYSTEM_CONTEXT_IA32 *ContextRecord\r
415 )\r
416/*++\r
417\r
418Routine Description: Common piece of code that invokes the registered handlers.\r
419\r
420 This code executes in exception context so no efi calls are allowed.\r
421\r
422Arguments:\r
423 ExceptionType - exception type\r
424 ContextRecord - system context\r
425\r
426Returns:\r
427\r
428 None\r
429\r
430--*/\r
431{\r
432 if (IdtEntryTable[ExceptionType].RegisteredCallback != NULL) {\r
433 if (ExceptionType != SYSTEM_TIMER_VECTOR) {\r
434 IdtEntryTable[ExceptionType].RegisteredCallback (ExceptionType, ContextRecord);\r
435 } else {\r
436 OrigVector = IdtEntryTable[ExceptionType].OrigVector;\r
437 IdtEntryTable[ExceptionType].RegisteredCallback (ContextRecord);\r
438 }\r
439 }\r
440}\r