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