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