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