]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Universal/DebugSupportDxe/Ia32/PlDebugSupport.c
Port AsmFuncs.s to pass CYGWINGCC build for x64.
[mirror_edk2.git] / MdeModulePkg / Universal / DebugSupportDxe / Ia32 / PlDebugSupport.c
... / ...
CommitLineData
1/** @file\r
2 Generic debug support functions for IA32/x64.\r
3\r
4Copyright (c) 2006 - 2008, 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#include "DebugSupport.h"\r
16\r
17//\r
18// This the global main table to keep track of the interrupts\r
19//\r
20IDT_ENTRY *IdtEntryTable = NULL;\r
21\r
22/**\r
23 Read IDT Gate Descriptor from IDT Table.\r
24\r
25 @param Vector Specifies vector number.\r
26 @param IdtGateDescriptor Pointer to IDT Gate Descriptor read from IDT Table.\r
27\r
28**/\r
29VOID\r
30ReadIdtGateDescriptor (\r
31 IN EFI_EXCEPTION_TYPE Vector,\r
32 OUT IA32_IDT_GATE_DESCRIPTOR *IdtGateDescriptor\r
33 )\r
34{\r
35 IA32_DESCRIPTOR IdtrValue;\r
36 IA32_IDT_GATE_DESCRIPTOR *IdtTable;\r
37\r
38 AsmReadIdtr (&IdtrValue);\r
39 IdtTable = (IA32_IDT_GATE_DESCRIPTOR *) IdtrValue.Base;\r
40\r
41 CopyMem ((VOID *) IdtGateDescriptor, (VOID *) &(IdtTable)[Vector], sizeof (IA32_IDT_GATE_DESCRIPTOR));\r
42}\r
43\r
44/**\r
45 Write IDT Gate Descriptor into IDT Table.\r
46\r
47 @param Vector Specifies vector number.\r
48 @param IdtGateDescriptor Pointer to IDT Gate Descriptor written into IDT Table.\r
49\r
50**/\r
51VOID\r
52WriteIdtGateDescriptor (\r
53 EFI_EXCEPTION_TYPE Vector,\r
54 IA32_IDT_GATE_DESCRIPTOR *IdtGateDescriptor\r
55 )\r
56{\r
57 IA32_DESCRIPTOR IdtrValue;\r
58 IA32_IDT_GATE_DESCRIPTOR *IdtTable;\r
59\r
60 AsmReadIdtr (&IdtrValue);\r
61 IdtTable = (IA32_IDT_GATE_DESCRIPTOR *) IdtrValue.Base;\r
62\r
63 CopyMem ((VOID *) &(IdtTable)[Vector], (VOID *) IdtGateDescriptor, sizeof (IA32_IDT_GATE_DESCRIPTOR));\r
64}\r
65\r
66/**\r
67 Creates a nes entry stub. Then saves the current IDT entry and replaces it\r
68 with an interrupt gate for the new entry point. The IdtEntryTable is updated\r
69 with the new registered function.\r
70\r
71 This code executes in boot services context. The stub entry executes in interrupt\r
72 context.\r
73\r
74 @param ExceptionType Specifies which vector to hook.\r
75 @param NewCallback A pointer to the new function to be registered.\r
76\r
77**/\r
78VOID\r
79HookEntry (\r
80 IN EFI_EXCEPTION_TYPE ExceptionType,\r
81 IN VOID (*NewCallback) ()\r
82 )\r
83{\r
84 BOOLEAN OldIntFlagState;\r
85\r
86 CreateEntryStub (ExceptionType, (VOID **) &IdtEntryTable[ExceptionType].StubEntry);\r
87 \r
88 //\r
89 // Disables CPU interrupts and returns the previous interrupt state\r
90 //\r
91 OldIntFlagState = SaveAndDisableInterrupts ();\r
92\r
93 ReadIdtGateDescriptor (ExceptionType, &(IdtEntryTable[ExceptionType].OrigDesc));\r
94 IdtEntryTable[ExceptionType].OrigVector = (DEBUG_PROC) GetInterruptHandleFromIdt (&(IdtEntryTable[ExceptionType].OrigDesc));\r
95\r
96 Vect2Desc (&IdtEntryTable[ExceptionType].NewDesc, IdtEntryTable[ExceptionType].StubEntry);\r
97 IdtEntryTable[ExceptionType].RegisteredCallback = NewCallback;\r
98 WriteIdtGateDescriptor (ExceptionType, &(IdtEntryTable[ExceptionType].NewDesc));\r
99\r
100 //\r
101 // restore interrupt state\r
102 //\r
103 SetInterruptState (OldIntFlagState);\r
104\r
105 return ;\r
106}\r
107\r
108/**\r
109 Undoes HookEntry. This code executes in boot services context.\r
110\r
111 @param ExceptionType Specifies which entry to unhook\r
112\r
113**/\r
114VOID\r
115UnhookEntry (\r
116 IN EFI_EXCEPTION_TYPE ExceptionType\r
117 )\r
118{\r
119 BOOLEAN OldIntFlagState;\r
120\r
121 //\r
122 // Disables CPU interrupts and returns the previous interrupt state\r
123 //\r
124 OldIntFlagState = SaveAndDisableInterrupts ();\r
125\r
126 //\r
127 // restore the default IDT Date Descriptor\r
128 //\r
129 WriteIdtGateDescriptor (ExceptionType, &(IdtEntryTable[ExceptionType].OrigDesc));\r
130\r
131 //\r
132 // restore interrupt state\r
133 //\r
134 SetInterruptState (OldIntFlagState);\r
135\r
136 return ;\r
137}\r
138\r
139/**\r
140 Returns the maximum value that may be used for the ProcessorIndex parameter in\r
141 RegisterPeriodicCallback() and RegisterExceptionCallback(). \r
142 \r
143 Hard coded to support only 1 processor for now.\r
144\r
145 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.\r
146 @param MaxProcessorIndex Pointer to a caller-allocated UINTN in which the maximum supported\r
147 processor index is returned. Always 0 returned. \r
148 \r
149 @retval EFI_SUCCESS Always returned with **MaxProcessorIndex set to 0.\r
150\r
151**/\r
152EFI_STATUS\r
153EFIAPI\r
154GetMaximumProcessorIndex (\r
155 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
156 OUT UINTN *MaxProcessorIndex\r
157 )\r
158{\r
159 *MaxProcessorIndex = 0;\r
160 return EFI_SUCCESS;\r
161}\r
162\r
163/**\r
164 Registers a function to be called back periodically in interrupt context.\r
165 \r
166 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.\r
167 @param ProcessorIndex Specifies which processor the callback function applies to.\r
168 @param PeriodicCallback A pointer to a function of type PERIODIC_CALLBACK that is the main\r
169 periodic entry point of the debug agent.\r
170 \r
171 @retval EFI_SUCCESS The function completed successfully. \r
172 @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a callback\r
173 function was previously registered. \r
174 @retval EFI_OUT_OF_RESOURCES System has insufficient memory resources to register new callback \r
175 function. \r
176**/\r
177EFI_STATUS\r
178EFIAPI\r
179RegisterPeriodicCallback (\r
180 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
181 IN UINTN ProcessorIndex,\r
182 IN EFI_PERIODIC_CALLBACK PeriodicCallback\r
183 )\r
184{\r
185 return ManageIdtEntryTable (PeriodicCallback, SYSTEM_TIMER_VECTOR);\r
186}\r
187\r
188/**\r
189 Registers a function to be called when a given processor exception occurs.\r
190\r
191 This code executes in boot services context.\r
192 \r
193 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.\r
194 @param ProcessorIndex Specifies which processor the callback function applies to.\r
195 @param ExceptionCallback A pointer to a function of type EXCEPTION_CALLBACK that is called\r
196 when the processor exception specified by ExceptionType occurs. \r
197 @param ExceptionType Specifies which processor exception to hook. \r
198 \r
199 @retval EFI_SUCCESS The function completed successfully. \r
200 @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a callback\r
201 function was previously registered. \r
202 @retval EFI_OUT_OF_RESOURCES System has insufficient memory resources to register new callback \r
203 function.\r
204**/\r
205EFI_STATUS\r
206EFIAPI\r
207RegisterExceptionCallback (\r
208 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
209 IN UINTN ProcessorIndex,\r
210 IN EFI_EXCEPTION_CALLBACK ExceptionCallback,\r
211 IN EFI_EXCEPTION_TYPE ExceptionType\r
212 )\r
213{\r
214 return ManageIdtEntryTable (ExceptionCallback, ExceptionType);\r
215}\r
216\r
217/**\r
218 Invalidates processor instruction cache for a memory range. Subsequent execution in this range\r
219 causes a fresh memory fetch to retrieve code to be executed. \r
220 \r
221 @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance.\r
222 @param ProcessorIndex Specifies which processor's instruction cache is to be invalidated.\r
223 @param Start Specifies the physical base of the memory range to be invalidated. \r
224 @param Length Specifies the minimum number of bytes in the processor's instruction\r
225 cache to invalidate. \r
226 \r
227 @retval EFI_SUCCESS Always returned.\r
228\r
229**/\r
230EFI_STATUS\r
231EFIAPI\r
232InvalidateInstructionCache (\r
233 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
234 IN UINTN ProcessorIndex,\r
235 IN VOID *Start,\r
236 IN UINT64 Length\r
237 )\r
238{\r
239 AsmWbinvd ();\r
240 return EFI_SUCCESS;\r
241}\r
242\r
243/**\r
244 Common piece of code that invokes the registered handlers.\r
245\r
246 This code executes in exception context so no efi calls are allowed.\r
247\r
248 @param ExceptionType Exception type\r
249 @param ContextRecord System context\r
250\r
251**/\r
252VOID\r
253InterruptDistrubutionHub (\r
254 EFI_EXCEPTION_TYPE ExceptionType,\r
255 EFI_SYSTEM_CONTEXT_IA32 *ContextRecord\r
256 )\r
257{\r
258 if (IdtEntryTable[ExceptionType].RegisteredCallback != NULL) {\r
259 if (ExceptionType != SYSTEM_TIMER_VECTOR) {\r
260 IdtEntryTable[ExceptionType].RegisteredCallback (ExceptionType, ContextRecord);\r
261 } else {\r
262 OrigVector = IdtEntryTable[ExceptionType].OrigVector;\r
263 IdtEntryTable[ExceptionType].RegisteredCallback (ContextRecord);\r
264 }\r
265 }\r
266}\r
267\r
268/**\r
269 This is the callback that is written to the Loaded Image protocol instance\r
270 on the image handle. It uninstalls all registered handlers and frees all entry\r
271 stub memory.\r
272\r
273 @param ImageHandle The firmware allocated handle for the EFI image.\r
274\r
275 @retval EFI_SUCCESS Always.\r
276\r
277**/\r
278EFI_STATUS\r
279EFIAPI\r
280PlUnloadDebugSupportDriver (\r
281 IN EFI_HANDLE ImageHandle\r
282 )\r
283{\r
284 EFI_EXCEPTION_TYPE ExceptionType;\r
285\r
286 for (ExceptionType = 0; ExceptionType < NUM_IDT_ENTRIES; ExceptionType++) {\r
287 ManageIdtEntryTable (NULL, ExceptionType);\r
288 //\r
289 // Free space for each Interrupt Stub precedure.\r
290 //\r
291 if (IdtEntryTable[ExceptionType].StubEntry != NULL) {\r
292 FreePool ((VOID *)(UINTN)IdtEntryTable[ExceptionType].StubEntry);\r
293 }\r
294 }\r
295\r
296 FreePool (IdtEntryTable);\r
297\r
298 return EFI_SUCCESS;\r
299}\r
300\r
301/**\r
302 Initializes driver's handler registration database. \r
303 \r
304 This code executes in boot services context.\r
305 Must be public because it's referenced from DebugSupport.c\r
306\r
307 @retval EFI_UNSUPPORTED If IA32/x64 processor does not support FXSTOR/FXRSTOR instructions,\r
308 the context save will fail, so these processors are not supported.\r
309 @retval EFI_OUT_OF_RESOURCES Fails to allocate memory.\r
310 @retval EFI_SUCCESS Initializes successfully.\r
311\r
312**/\r
313EFI_STATUS\r
314PlInitializeDebugSupportDriver (\r
315 VOID\r
316 )\r
317{\r
318 EFI_EXCEPTION_TYPE ExceptionType;\r
319\r
320 //\r
321 // Check whether FxStor instructions are supported.\r
322 //\r
323 if (!FxStorSupport ()) {\r
324 return EFI_UNSUPPORTED;\r
325 }\r
326\r
327 IdtEntryTable = AllocateZeroPool (sizeof (IDT_ENTRY) * NUM_IDT_ENTRIES);\r
328 if (IdtEntryTable == NULL) {\r
329 return EFI_OUT_OF_RESOURCES;\r
330 }\r
331\r
332 for (ExceptionType = 0; ExceptionType < NUM_IDT_ENTRIES; ExceptionType ++) {\r
333 IdtEntryTable[ExceptionType].StubEntry = (DEBUG_PROC) (UINTN) AllocatePool (StubSize);\r
334 if (IdtEntryTable[ExceptionType].StubEntry == NULL) {\r
335 goto ErrorCleanup;\r
336 }\r
337 \r
338 //\r
339 // Copy Interrupt stub code.\r
340 //\r
341 CopyMem ((VOID *)(UINTN)IdtEntryTable[ExceptionType].StubEntry, InterruptEntryStub, StubSize);\r
342 }\r
343 return EFI_SUCCESS;\r
344\r
345ErrorCleanup:\r
346\r
347 for (ExceptionType = 0; ExceptionType < NUM_IDT_ENTRIES; ExceptionType++) {\r
348 if (IdtEntryTable[ExceptionType].StubEntry != NULL) {\r
349 FreePool ((VOID *)(UINTN)IdtEntryTable[ExceptionType].StubEntry);\r
350 }\r
351 }\r
352 FreePool (IdtEntryTable);\r
353\r
354 return EFI_OUT_OF_RESOURCES;\r
355}\r