PlDebugSupport.c revision 6e8a984eca4c9763038e887b8d813b2110bbaed6
1/** @file
2  IA32 specific debug support functions
3
4Copyright (c) 2006 - 2008, Intel Corporation
5All rights reserved. This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution.  The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13**/
14
15//
16// private header files
17//
18#include "DebugSupport.h"
19
20//
21// This the global main table to keep track of the interrupts
22//
23IDT_ENTRY   *IdtEntryTable  = NULL;
24IA32_IDT_GATE_DESCRIPTOR  NullDesc        = {0};
25
26/**
27  Read IDT Gate Descriptor from IDT Table.
28
29  @param  Vector            Specifies vector number.
30  @param  IdtGateDecriptor  Pointer to IDT Gate Descriptor read from IDT Table.
31
32**/
33VOID ReadIdtGateDecriptor (
34  IN  EFI_EXCEPTION_TYPE        Vector,
35  OUT IA32_IDT_GATE_DESCRIPTOR  *IdtGateDecriptor
36  )
37{
38 IA32_DESCRIPTOR            IdtrValue;
39 IA32_IDT_GATE_DESCRIPTOR   *IdtTable;
40
41 AsmReadIdtr (&IdtrValue);
42 IdtTable = (IA32_IDT_GATE_DESCRIPTOR *) IdtrValue.Base;
43
44 CopyMem ((VOID *) IdtGateDecriptor, (VOID *) &(IdtTable)[Vector], sizeof (IA32_IDT_GATE_DESCRIPTOR));
45}
46/**
47  Write IDT Gate Descriptor into IDT Table.
48
49  @param  Vector            Specifies vector number.
50  @param  IdtGateDecriptor  Pointer to IDT Gate Descriptor written into IDT Table.
51
52**/
53VOID WriteIdtGateDecriptor (
54  EFI_EXCEPTION_TYPE        Vector,
55  IA32_IDT_GATE_DESCRIPTOR  *IdtGateDecriptor
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 *) IdtGateDecriptor, sizeof (IA32_IDT_GATE_DESCRIPTOR));
65}
66
67
68/**
69  Creates a nes entry stub.  Then saves the current IDT entry and replaces it
70  with an interrupt gate for the new entry point.  The IdtEntryTable is updated
71  with the new registered function.
72
73  This code executes in boot services context.  The stub entry executes in interrupt
74  context.
75
76  @param  ExceptionType      Specifies which vector to hook.
77  @param  NewCallback        A pointer to the new function to be registered.
78
79  @retval EFI_SUCCESS        Always.
80
81**/
82EFI_STATUS
83HookEntry (
84  IN EFI_EXCEPTION_TYPE            ExceptionType,
85  IN VOID                         (*NewCallback) ()
86  )
87{
88  BOOLEAN     OldIntFlagState;
89  EFI_STATUS  Status;
90
91  Status = CreateEntryStub (ExceptionType, (VOID **) &IdtEntryTable[ExceptionType].StubEntry);
92  if (Status == EFI_SUCCESS) {
93    OldIntFlagState = WriteInterruptFlag (0);
94    ReadIdtGateDecriptor (ExceptionType, &(IdtEntryTable[ExceptionType].OrigDesc));
95
96    IdtEntryTable[ExceptionType].OrigVector = (DEBUG_PROC) GetProcedureEntryPoint (&(IdtEntryTable[ExceptionType].OrigDesc));
97
98    Vect2Desc (&IdtEntryTable[ExceptionType].NewDesc, IdtEntryTable[ExceptionType].StubEntry);
99    IdtEntryTable[ExceptionType].RegisteredCallback = NewCallback;
100    WriteIdtGateDecriptor (ExceptionType, &(IdtEntryTable[ExceptionType].NewDesc));
101    WriteInterruptFlag (OldIntFlagState);
102  }
103
104  return Status;
105}
106
107/**
108  Undoes HookEntry. This code executes in boot services context.
109
110  @param  ExceptionType   Specifies which entry to unhook
111
112  @retval EFI_SUCCESS     Always.
113
114**/
115EFI_STATUS
116UnhookEntry (
117  IN EFI_EXCEPTION_TYPE           ExceptionType
118  )
119{
120  BOOLEAN     OldIntFlagState;
121
122  OldIntFlagState = WriteInterruptFlag (0);
123  WriteIdtGateDecriptor (ExceptionType, &(IdtEntryTable[ExceptionType].OrigDesc));
124  WriteInterruptFlag (OldIntFlagState);
125
126  return EFI_SUCCESS;
127}
128
129/**
130  This is a DebugSupport protocol member function, hard
131  coded to support only 1 processor for now.
132
133  @param  This                The DebugSupport instance
134  @param  MaxProcessorIndex   The maximuim supported processor index
135
136  @retval EFI_SUCCESS         Always returned with **MaxProcessorIndex set to 0.
137
138**/
139EFI_STATUS
140EFIAPI
141GetMaximumProcessorIndex (
142  IN EFI_DEBUG_SUPPORT_PROTOCOL       *This,
143  OUT UINTN                           *MaxProcessorIndex
144  )
145{
146  *MaxProcessorIndex = 0;
147  return (EFI_SUCCESS);
148}
149
150/**
151  DebugSupport protocol member function.
152
153  @param  This               The DebugSupport instance
154  @param  ProcessorIndex     Which processor the callback applies to.
155  @param  PeriodicCallback   Callback function
156
157  @retval EFI_SUCCESS        Indicates the callback was registered.
158  @retval others             Callback was not registered.
159
160**/
161EFI_STATUS
162EFIAPI
163RegisterPeriodicCallback (
164  IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
165  IN UINTN                      ProcessorIndex,
166  IN EFI_PERIODIC_CALLBACK      PeriodicCallback
167  )
168{
169  return ManageIdtEntryTable (PeriodicCallback, SYSTEM_TIMER_VECTOR);
170}
171
172/**
173  DebugSupport protocol member function.
174
175  This code executes in boot services context.
176
177  @param  This              The DebugSupport instance
178  @param  ProcessorIndex    Which processor the callback applies to.
179  @param  NewCallback       Callback function
180  @param  ExceptionType     Which exception to hook
181
182  @retval EFI_SUCCESS        Indicates the callback was registered.
183  @retval others             Callback was not registered.
184
185**/
186EFI_STATUS
187EFIAPI
188RegisterExceptionCallback (
189  IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
190  IN UINTN                      ProcessorIndex,
191  IN EFI_EXCEPTION_CALLBACK     NewCallback,
192  IN EFI_EXCEPTION_TYPE         ExceptionType
193  )
194{
195  return ManageIdtEntryTable (NewCallback, ExceptionType);
196}
197
198/**
199  DebugSupport protocol member function.  Calls assembly routine to flush cache.
200
201  @param  This              The DebugSupport instance
202  @param  ProcessorIndex    Which processor the callback applies to.
203  @param  Start             Physical base of the memory range to be invalidated
204  @param  Length            mininum number of bytes in instruction cache to invalidate
205
206  @retval EFI_SUCCESS       Always returned.
207
208**/
209EFI_STATUS
210EFIAPI
211InvalidateInstructionCache (
212  IN EFI_DEBUG_SUPPORT_PROTOCOL       *This,
213  IN UINTN                            ProcessorIndex,
214  IN VOID                             *Start,
215  IN UINT64                           Length
216  )
217{
218  AsmWbinvd ();
219  return EFI_SUCCESS;
220}
221
222/**
223  Initializes driver's handler registration databas.
224
225  This code executes in boot services context
226  Must be public because it's referenced from DebugSupport.c
227
228  @retval  EFI_UNSUPPORTED      If IA32 processor does not support FXSTOR/FXRSTOR instructions,
229                                the context save will fail, so these processor's are not supported.
230  @retval  EFI_OUT_OF_RESOURCES Fails to allocate memory.
231  @retval  EFI_SUCCESS          Initializes successfully.
232
233**/
234EFI_STATUS
235PlInitializeDebugSupportDriver (
236  VOID
237  )
238{
239  EFI_EXCEPTION_TYPE  ExceptionType;
240
241  if (!FxStorSupport ()) {
242    return EFI_UNSUPPORTED;
243  }
244
245  IdtEntryTable = AllocateZeroPool (sizeof (IDT_ENTRY) * NUM_IDT_ENTRIES);
246  if (IdtEntryTable == NULL) {
247    return EFI_OUT_OF_RESOURCES;
248  }
249
250  for (ExceptionType = 0; ExceptionType < NUM_IDT_ENTRIES; ExceptionType++) {
251    IdtEntryTable[ExceptionType].StubEntry = (DEBUG_PROC) (UINTN) AllocatePool (StubSize);
252    if (IdtEntryTable[ExceptionType].StubEntry == NULL) {
253      goto ErrorCleanup;
254    }
255
256    CopyMem ((VOID *)(UINTN)IdtEntryTable[ExceptionType].StubEntry, InterruptEntryStub, StubSize);
257  }
258  return EFI_SUCCESS;
259
260ErrorCleanup:
261
262  for (ExceptionType = 0; ExceptionType < NUM_IDT_ENTRIES; ExceptionType++) {
263    if (IdtEntryTable[ExceptionType].StubEntry != NULL) {
264      FreePool ((VOID *)(UINTN)IdtEntryTable[ExceptionType].StubEntry);
265    }
266  }
267  FreePool (IdtEntryTable);
268
269  return EFI_OUT_OF_RESOURCES;
270}
271
272/**
273  This is the callback that is written to the LoadedImage protocol instance
274  on the image handle. It uninstalls all registered handlers and frees all entry
275  stub memory.
276
277  @param  ImageHandle    The firmware allocated handle for the EFI image.
278
279  @retval EFI_SUCCESS    Always.
280
281**/
282EFI_STATUS
283EFIAPI
284PlUnloadDebugSupportDriver (
285  IN EFI_HANDLE ImageHandle
286  )
287{
288  EFI_EXCEPTION_TYPE  ExceptionType;
289
290  for (ExceptionType = 0; ExceptionType < NUM_IDT_ENTRIES; ExceptionType++) {
291    ManageIdtEntryTable (NULL, ExceptionType);
292  }
293
294  FreePool (IdtEntryTable);
295  return EFI_SUCCESS;
296}
297
298/**
299  Common piece of code that invokes the registered handlers.
300
301  This code executes in exception context so no efi calls are allowed.
302
303  @param  ExceptionType     Exception type
304  @param  ContextRecord     System context
305
306**/
307VOID
308InterruptDistrubutionHub (
309  EFI_EXCEPTION_TYPE      ExceptionType,
310  EFI_SYSTEM_CONTEXT_IA32 *ContextRecord
311  )
312{
313  if (IdtEntryTable[ExceptionType].RegisteredCallback != NULL) {
314    if (ExceptionType != SYSTEM_TIMER_VECTOR) {
315      IdtEntryTable[ExceptionType].RegisteredCallback (ExceptionType, ContextRecord);
316    } else {
317      OrigVector = IdtEntryTable[ExceptionType].OrigVector;
318      IdtEntryTable[ExceptionType].RegisteredCallback (ContextRecord);
319    }
320  }
321}
322