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