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