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