2198192a0402cd0de8086b78b0312ca83bb8efcd
[mirror_edk2.git] / EdkModulePkg / Universal / DebugSupport / Dxe / Ia32 / plDebugSupport.c
1 /*++
2
3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 plDebugSupport.c
15
16 Abstract:
17
18 IA32 specific debug support functions
19
20 Revision History
21
22 --*/
23
24 //
25 // private header files
26 //
27 #include "plDebugSupport.h"
28
29 //
30 // This the global main table to keep track of the interrupts
31 //
32 IDT_ENTRY *IdtEntryTable = NULL;
33 DESCRIPTOR NullDesc = 0;
34
35 #ifndef EFI_NT_EMULATOR
36 STATIC
37 EFI_STATUS
38 CreateEntryStub (
39 IN EFI_EXCEPTION_TYPE ExceptionType,
40 OUT VOID **Stub
41 )
42 /*++
43
44 Routine Description: Allocate pool for a new IDT entry stub. Copy the generic
45 stub into the new buffer and fixup the vector number and jump target address.
46
47 Arguments:
48 ExceptionType - This is the exception type that the new stub will be created
49 for.
50 Stub - On successful exit, *Stub contains the newly allocated entry stub.
51 Returns:
52 Typically EFI_SUCCESS
53 other possibilities are passed through from AllocatePool
54
55 --*/
56 {
57 EFI_STATUS Status;
58 UINT8 *StubCopy;
59
60 //
61 // First, allocate a new buffer and copy the stub code into it
62 //
63 Status = gBS->AllocatePool (EfiBootServicesData, StubSize, Stub);
64 if (Status == EFI_SUCCESS) {
65 StubCopy = *Stub;
66 gBS->CopyMem (StubCopy, InterruptEntryStub, StubSize);
67
68 //
69 // Next fixup the stub code for this vector
70 //
71
72 // The stub code looks like this:
73 //
74 // 00000000 89 25 00000004 R mov AppEsp, esp ; save stack top
75 // 00000006 BC 00008014 R mov esp, offset DbgStkBot ; switch to debugger stack
76 // 0000000B 6A 00 push 0 ; push vector number - will be modified before installed
77 // 0000000D E9 db 0e9h ; jump rel32
78 // 0000000E 00000000 dd 0 ; fixed up to relative address of CommonIdtEntry
79 //
80
81 //
82 // poke in the exception type so the second push pushes the exception type
83 //
84 StubCopy[0x0c] = (UINT8) ExceptionType;
85
86 //
87 // fixup the jump target to point to the common entry
88 //
89 *(UINT32 *) &StubCopy[0x0e] = (UINT32) CommonIdtEntry - (UINT32) &StubCopy[StubSize];
90 }
91
92 return Status;
93 }
94
95 STATIC
96 EFI_STATUS
97 HookEntry (
98 IN EFI_EXCEPTION_TYPE ExceptionType,
99 IN VOID (*NewCallback) ()
100 )
101 /*++
102
103 Routine Description:
104 Creates a nes entry stub. Then saves the current IDT entry and replaces it
105 with an interrupt gate for the new entry point. The IdtEntryTable is updated
106 with the new registered function.
107
108 This code executes in boot services context. The stub entry executes in interrupt
109 context.
110
111 Arguments:
112 ExceptionType - specifies which vector to hook.
113 NewCallback - a pointer to the new function to be registered.
114
115 Returns:
116 EFI_SUCCESS
117 Other possibilities are passed through by CreateEntryStub
118
119 --*/
120 // TODO: ) - add argument and description to function comment
121 {
122 BOOLEAN OldIntFlagState;
123 EFI_STATUS Status;
124
125 Status = CreateEntryStub (ExceptionType, (VOID **) &IdtEntryTable[ExceptionType].StubEntry);
126 if (Status == EFI_SUCCESS) {
127 OldIntFlagState = WriteInterruptFlag (0);
128 ReadIdt (ExceptionType, &(IdtEntryTable[ExceptionType].OrigDesc));
129
130 ((UINT16 *) &IdtEntryTable[ExceptionType].OrigVector)[0] = ((UINT16 *) &IdtEntryTable[ExceptionType].OrigDesc)[0];
131 ((UINT16 *) &IdtEntryTable[ExceptionType].OrigVector)[1] = ((UINT16 *) &IdtEntryTable[ExceptionType].OrigDesc)[3];
132
133 Vect2Desc (&IdtEntryTable[ExceptionType].NewDesc, IdtEntryTable[ExceptionType].StubEntry);
134 IdtEntryTable[ExceptionType].RegisteredCallback = NewCallback;
135 WriteIdt (ExceptionType, &(IdtEntryTable[ExceptionType].NewDesc));
136 WriteInterruptFlag (OldIntFlagState);
137 }
138
139 return Status;
140 }
141
142 STATIC
143 EFI_STATUS
144 UnhookEntry (
145 IN EFI_EXCEPTION_TYPE ExceptionType
146 )
147 /*++
148
149 Routine Description:
150 Undoes HookEntry. This code executes in boot services context.
151
152 Arguments:
153 ExceptionType - specifies which entry to unhook
154
155 Returns:
156 EFI_SUCCESS
157 Other values are passed through from FreePool
158
159 --*/
160 {
161 BOOLEAN OldIntFlagState;
162 EFI_STATUS Status;
163
164 OldIntFlagState = WriteInterruptFlag (0);
165 WriteIdt (ExceptionType, &(IdtEntryTable[ExceptionType].OrigDesc));
166 Status = gBS->FreePool ((VOID *) (UINTN) IdtEntryTable[ExceptionType].StubEntry);
167 ZeroMem (&IdtEntryTable[ExceptionType], sizeof (IDT_ENTRY));
168 WriteInterruptFlag (OldIntFlagState);
169
170 return (Status);
171 }
172 #endif
173
174 EFI_STATUS
175 ManageIdtEntryTable (
176 VOID (*NewCallback)(),
177 EFI_EXCEPTION_TYPE ExceptionType
178 )
179 /*++
180
181 Routine Description:
182 This is the main worker function that manages the state of the interrupt
183 handlers. It both installs and uninstalls interrupt handlers based on the
184 value of NewCallback. If NewCallback is NULL, then uninstall is indicated.
185 If NewCallback is non-NULL, then install is indicated.
186
187 Arguments:
188 NewCallback - If non-NULL, NewCallback specifies the new handler to register.
189 If NULL, specifies that the previously registered handler should
190 be uninstalled.
191 ExceptionType - Indicates which entry to manage
192
193 Returns:
194 EFI_SUCCESS
195 EFI_INVALID_PARAMETER - requested uninstalling a handler from a vector that has
196 no handler registered for it
197 EFI_ALREADY_STARTED - requested install to a vector that already has a handler registered.
198
199 Other possible return values are passed through from UnHookEntry and HookEntry.
200
201 --*/
202 // TODO: ) - add argument and description to function comment
203 {
204 EFI_STATUS Status;
205
206 Status = EFI_SUCCESS;
207
208 #ifndef EFI_NT_EMULATOR
209 if (CompareDescriptor (&IdtEntryTable[ExceptionType].NewDesc, &NullDesc)) {
210 //
211 // we've already installed to this vector
212 //
213 if (NewCallback != NULL) {
214 //
215 // if the input handler is non-null, error
216 //
217 Status = EFI_ALREADY_STARTED;
218 } else {
219 Status = UnhookEntry (ExceptionType);
220 }
221 } else {
222 //
223 // no user handler installed on this vector
224 //
225 if (NewCallback == NULL) {
226 //
227 // if the input handler is null, error
228 //
229 Status = EFI_INVALID_PARAMETER;
230 } else {
231 Status = HookEntry (ExceptionType, NewCallback);
232 }
233 }
234 #endif
235 return Status;
236 }
237
238 EFI_STATUS
239 EFIAPI
240 GetMaximumProcessorIndex (
241 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
242 OUT UINTN *MaxProcessorIndex
243 )
244 /*++
245
246 Routine Description: This is a DebugSupport protocol member function.
247
248 Arguments:
249
250 Returns: Always returns EFI_SUCCESS with *MaxProcessorIndex set to 0
251
252 --*/
253 // TODO: This - add argument and description to function comment
254 // TODO: MaxProcessorIndex - add argument and description to function comment
255 {
256 *MaxProcessorIndex = 0;
257 return (EFI_SUCCESS);
258 }
259
260 EFI_STATUS
261 EFIAPI
262 RegisterPeriodicCallback (
263 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
264 IN UINTN ProcessorIndex,
265 IN EFI_PERIODIC_CALLBACK PeriodicCallback
266 )
267 /*++
268
269 Routine Description: This is a DebugSupport protocol member function.
270
271 Arguments:
272
273 Returns:
274
275 --*/
276 // TODO: This - add argument and description to function comment
277 // TODO: ProcessorIndex - add argument and description to function comment
278 // TODO: PeriodicCallback - add argument and description to function comment
279 {
280 return ManageIdtEntryTable (PeriodicCallback, SYSTEM_TIMER_VECTOR);
281 }
282
283 EFI_STATUS
284 EFIAPI
285 RegisterExceptionCallback (
286 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
287 IN UINTN ProcessorIndex,
288 IN EFI_EXCEPTION_CALLBACK NewCallback,
289 IN EFI_EXCEPTION_TYPE ExceptionType
290 )
291 /*++
292
293 Routine Description:
294 This is a DebugSupport protocol member function.
295
296 This code executes in boot services context.
297
298 Arguments:
299
300 Returns:
301
302 None
303
304 --*/
305 // TODO: This - add argument and description to function comment
306 // TODO: ProcessorIndex - add argument and description to function comment
307 // TODO: NewCallback - add argument and description to function comment
308 // TODO: ExceptionType - add argument and description to function comment
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 For IA32, this is a no-op since the instruction and data caches are coherent.
326
327 Arguments:
328
329 Returns:
330
331 None
332
333 --*/
334 // TODO: This - add argument and description to function comment
335 // TODO: ProcessorIndex - add argument and description to function comment
336 // TODO: Start - add argument and description to function comment
337 // TODO: Length - add argument and description to function comment
338 // TODO: EFI_SUCCESS - add return value to function comment
339 {
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
362 --*/
363 // TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
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 None
397
398 --*/
399 // TODO: EFI_SUCCESS - add return value to function comment
400 {
401 EFI_EXCEPTION_TYPE ExceptionType;
402
403 for (ExceptionType = 0; ExceptionType < NUM_IDT_ENTRIES; ExceptionType++) {
404 ManageIdtEntryTable (NULL, ExceptionType);
405 }
406
407 gBS->FreePool (IdtEntryTable);
408 return EFI_SUCCESS;
409 }
410
411 VOID
412 InterruptDistrubutionHub (
413 EFI_EXCEPTION_TYPE ExceptionType,
414 EFI_SYSTEM_CONTEXT_IA32 *ContextRecord
415 )
416 /*++
417
418 Routine Description: Common piece of code that invokes the registered handlers.
419
420 This code executes in exception context so no efi calls are allowed.
421
422 Arguments:
423
424 Returns:
425
426 None
427
428 --*/
429 // TODO: ExceptionType - add argument and description to function comment
430 // TODO: ContextRecord - add argument and description to function comment
431 {
432 if (IdtEntryTable[ExceptionType].RegisteredCallback != NULL) {
433 if (ExceptionType != SYSTEM_TIMER_VECTOR) {
434 IdtEntryTable[ExceptionType].RegisteredCallback (ExceptionType, ContextRecord);
435 } else {
436 OrigVector = IdtEntryTable[ExceptionType].OrigVector;
437 IdtEntryTable[ExceptionType].RegisteredCallback (ContextRecord);
438 }
439 }
440 }