Home | History | Annotate | Download | only in SmmDebugAgent
      1 /** @file
      2   Debug Agent library implementition.
      3 
      4   Copyright (c) 2010 - 2015, 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 "SmmDebugAgentLib.h"
     16 
     17 DEBUG_AGENT_MAILBOX         *mMailboxPointer = NULL;
     18 DEBUG_AGENT_MAILBOX         mLocalMailbox;
     19 UINTN                       mSavedDebugRegisters[6];
     20 IA32_IDT_GATE_DESCRIPTOR    mIdtEntryTable[33];
     21 BOOLEAN                     mSkipBreakpoint = FALSE;
     22 
     23 CHAR8 mWarningMsgIgnoreSmmEntryBreak[] = "Ignore smmentrybreak setting for SMI issued during DXE debugging!\r\n";
     24 
     25 /**
     26   Check if debug agent support multi-processor.
     27 
     28   @retval TRUE    Multi-processor is supported.
     29   @retval FALSE   Multi-processor is not supported.
     30 
     31 **/
     32 BOOLEAN
     33 MultiProcessorDebugSupport (
     34   VOID
     35   )
     36 {
     37   return FALSE;
     38 }
     39 
     40 /**
     41   Read the Attach/Break-in symbols from the debug port.
     42 
     43   @param[in]  Handle         Pointer to Debug Port handle.
     44   @param[out] BreakSymbol    Returned break symbol.
     45 
     46   @retval EFI_SUCCESS        Read the symbol in BreakSymbol.
     47   @retval EFI_NOT_FOUND      No read the break symbol.
     48 
     49 **/
     50 EFI_STATUS
     51 DebugReadBreakSymbol (
     52   IN  DEBUG_PORT_HANDLE      Handle,
     53   OUT UINT8                  *BreakSymbol
     54   )
     55 {
     56   //
     57   // Smm instance has no debug timer to poll break symbol.
     58   //
     59   return EFI_NOT_FOUND;
     60 }
     61 
     62 /**
     63   Get the pointer to Mailbox from the GUIDed HOB.
     64 
     65   @return Pointer to Mailbox.
     66 
     67 **/
     68 DEBUG_AGENT_MAILBOX *
     69 GetMailboxFromHob (
     70   VOID
     71   )
     72 {
     73   EFI_HOB_GUID_TYPE        *GuidHob;
     74   UINT64                   *MailboxLocation;
     75   DEBUG_AGENT_MAILBOX      *Mailbox;
     76 
     77   GuidHob = GetFirstGuidHob (&gEfiDebugAgentGuid);
     78   if (GuidHob == NULL) {
     79     return NULL;
     80   }
     81   MailboxLocation = (UINT64 *) (GET_GUID_HOB_DATA(GuidHob));
     82   Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
     83   VerifyMailboxChecksum (Mailbox);
     84 
     85   return Mailbox;
     86 }
     87 
     88 /**
     89   Get Debug Agent Mailbox pointer.
     90 
     91   @return Mailbox pointer.
     92 
     93 **/
     94 DEBUG_AGENT_MAILBOX *
     95 GetMailboxPointer (
     96   VOID
     97   )
     98 {
     99   VerifyMailboxChecksum (mMailboxPointer);
    100   return mMailboxPointer;
    101 }
    102 
    103 /**
    104   Get debug port handle.
    105 
    106   @return Debug port handle.
    107 
    108 **/
    109 DEBUG_PORT_HANDLE
    110 GetDebugPortHandle (
    111   VOID
    112   )
    113 {
    114   return (DEBUG_PORT_HANDLE) (UINTN)(GetMailboxPointer()->DebugPortHandle);
    115 }
    116 
    117 /**
    118   Store debug register when SMI exit.
    119 
    120 **/
    121 VOID
    122 SaveDebugRegister (
    123   VOID
    124   )
    125 {
    126   mSavedDebugRegisters[0] = AsmReadDr0 ();
    127   mSavedDebugRegisters[1] = AsmReadDr1 ();
    128   mSavedDebugRegisters[2] = AsmReadDr2 ();
    129   mSavedDebugRegisters[3] = AsmReadDr3 ();
    130   mSavedDebugRegisters[4] = AsmReadDr6 ();
    131   mSavedDebugRegisters[5] = AsmReadDr7 ();
    132 }
    133 
    134 /**
    135   Restore debug register when SMI exit.
    136 
    137 **/
    138 VOID
    139 RestoreDebugRegister (
    140   VOID
    141   )
    142 {
    143   AsmWriteDr7 (0);
    144   AsmWriteDr0 (mSavedDebugRegisters[0]);
    145   AsmWriteDr1 (mSavedDebugRegisters[1]);
    146   AsmWriteDr2 (mSavedDebugRegisters[2]);
    147   AsmWriteDr3 (mSavedDebugRegisters[3]);
    148   AsmWriteDr6 (mSavedDebugRegisters[4]);
    149   AsmWriteDr7 (mSavedDebugRegisters[5]);
    150 }
    151 
    152 /**
    153   Initialize debug agent.
    154 
    155   This function is used to set up debug enviroment for source level debug
    156   in SMM code.
    157 
    158   If InitFlag is DEBUG_AGENT_INIT_SMM, it will overirde IDT table entries
    159   and initialize debug port. It will get debug agent Mailbox from GUIDed HOB,
    160   it it exists, debug agent wiil copied it into the local Mailbox in SMM space.
    161   it will overirde IDT table entries and initialize debug port. Context will be
    162   NULL.
    163   If InitFlag is DEBUG_AGENT_INIT_ENTER_SMI, debug agent will save Debug
    164   Registers and get local Mailbox in SMM space. Context will be NULL.
    165   If InitFlag is DEBUG_AGENT_INIT_EXIT_SMI, debug agent will restore Debug
    166   Registers. Context will be NULL.
    167 
    168   @param[in] InitFlag     Init flag is used to decide initialize process.
    169   @param[in] Context      Context needed according to InitFlag.
    170   @param[in] Function     Continue function called by debug agent library; it was
    171                           optional.
    172 
    173 **/
    174 VOID
    175 EFIAPI
    176 InitializeDebugAgent (
    177   IN UINT32                InitFlag,
    178   IN VOID                  *Context, OPTIONAL
    179   IN DEBUG_AGENT_CONTINUE  Function  OPTIONAL
    180   )
    181 {
    182   EFI_STATUS                    Status;
    183   UINT64                        DebugPortHandle;
    184   IA32_IDT_GATE_DESCRIPTOR      IdtEntry[33];
    185   IA32_DESCRIPTOR               IdtDescriptor;
    186   IA32_DESCRIPTOR               *Ia32Idtr;
    187   IA32_IDT_ENTRY                *Ia32IdtEntry;
    188   IA32_DESCRIPTOR               Idtr;
    189   UINT16                        IdtEntryCount;
    190   DEBUG_AGENT_MAILBOX           *Mailbox;
    191   UINT64                        *MailboxLocation;
    192   UINT32                        DebugTimerFrequency;
    193   BOOLEAN                       PeriodicMode;
    194   UINTN                         TimerCycle;
    195 
    196   switch (InitFlag) {
    197   case DEBUG_AGENT_INIT_SMM:
    198     //
    199     // Install configuration table for persisted vector handoff info
    200     //
    201     Status = gSmst->SmmInstallConfigurationTable (
    202                       gSmst,
    203                       &gEfiVectorHandoffTableGuid,
    204                       (VOID *) &mVectorHandoffInfoDebugAgent[0],
    205                       sizeof (EFI_VECTOR_HANDOFF_INFO) * mVectorHandoffInfoCount
    206                       );
    207     if (EFI_ERROR (Status)) {
    208       DEBUG ((EFI_D_ERROR, "DebugAgent: Cannot install configuration table for persisted vector handoff info!\n"));
    209       CpuDeadLoop ();
    210     }
    211     //
    212     // Check if Debug Agent initialized in DXE phase
    213     //
    214     Status = EfiGetSystemConfigurationTable (&gEfiDebugAgentGuid, (VOID **) &Mailbox);
    215     if (Status == EFI_SUCCESS && Mailbox != NULL) {
    216       VerifyMailboxChecksum (Mailbox);
    217       mMailboxPointer = Mailbox;
    218       break;
    219     }
    220     //
    221     // Check if Debug Agent initialized in SEC/PEI phase
    222     //
    223     Mailbox = GetMailboxFromHob ();
    224     if (Mailbox != NULL) {
    225       mMailboxPointer = Mailbox;
    226       break;
    227     }
    228     //
    229     // Debug Agent was not initialized before, use the local mailbox.
    230     //
    231     ZeroMem (&mLocalMailbox, sizeof (DEBUG_AGENT_MAILBOX));
    232     Mailbox = &mLocalMailbox;
    233     //
    234     // Save original IDT entries
    235     //
    236     AsmReadIdtr (&IdtDescriptor);
    237     CopyMem (&IdtEntry, (VOID *)IdtDescriptor.Base, 33 * sizeof(IA32_IDT_GATE_DESCRIPTOR));
    238     //
    239     // Initialized Debug Agent
    240     //
    241     InitializeDebugIdt ();
    242     //
    243     // Initialize Debug Timer hardware and save its frequency
    244     //
    245     InitializeDebugTimer (&DebugTimerFrequency, TRUE);
    246     UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency);
    247 
    248     DebugPortHandle = (UINT64) (UINTN)DebugPortInitialize ((DEBUG_PORT_HANDLE) (UINTN)Mailbox->DebugPortHandle, NULL);
    249     UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
    250     mMailboxPointer = Mailbox;
    251     //
    252     // Trigger one software interrupt to inform HOST
    253     //
    254     TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE);
    255 
    256     SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
    257     //
    258     // Memory has been ready
    259     //
    260     if (IsHostAttached ()) {
    261       //
    262       // Trigger one software interrupt to inform HOST
    263       //
    264       TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
    265     }
    266     //
    267     // Find and report PE/COFF image info to HOST
    268     //
    269     FindAndReportModuleImageInfo (SIZE_4KB);
    270     //
    271     // Restore saved IDT entries
    272     //
    273     CopyMem ((VOID *)IdtDescriptor.Base, &IdtEntry, 33 * sizeof(IA32_IDT_GATE_DESCRIPTOR));
    274 
    275     break;
    276 
    277   case DEBUG_AGENT_INIT_ENTER_SMI:
    278     SaveDebugRegister ();
    279     InitializeDebugIdt ();
    280     //
    281     // Check if CPU APIC Timer is working, otherwise initialize it.
    282     //
    283     InitializeLocalApicSoftwareEnable (TRUE);
    284     GetApicTimerState (NULL, &PeriodicMode, NULL);
    285     TimerCycle = GetApicTimerInitCount ();
    286     if (!PeriodicMode || TimerCycle == 0) {
    287       InitializeDebugTimer (NULL, FALSE);
    288     }
    289     Mailbox = GetMailboxPointer ();
    290     if (GetDebugFlag (DEBUG_AGENT_FLAG_AGENT_IN_PROGRESS) == 1) {
    291       //
    292       // If Debug Agent has been communicaton state with HOST, we need skip
    293       // any break points set in SMM, set Skip Breakpoint flag
    294       //
    295       mSkipBreakpoint = TRUE;
    296     }
    297     if (GetDebugFlag (DEBUG_AGENT_FLAG_BREAK_ON_NEXT_SMI) == 1) {
    298       if (mSkipBreakpoint) {
    299         //
    300         // Print warning message if ignore smm entry break
    301         //
    302         DebugPortWriteBuffer ((DEBUG_PORT_HANDLE) (UINTN)Mailbox->DebugPortHandle,
    303                                (UINT8 *)mWarningMsgIgnoreSmmEntryBreak,
    304                                AsciiStrLen (mWarningMsgIgnoreSmmEntryBreak)
    305                                );
    306       } else {
    307         //
    308         // If SMM entry break is set, SMM code will be break at here.
    309         //
    310         CpuBreakpoint ();
    311       }
    312     }
    313     break;
    314 
    315   case DEBUG_AGENT_INIT_EXIT_SMI:
    316     Mailbox = GetMailboxPointer ();
    317     //
    318     // Clear Skip Breakpoint flag
    319     //
    320     mSkipBreakpoint = FALSE;
    321     RestoreDebugRegister ();
    322     break;
    323 
    324   case DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64:
    325     if (Context == NULL) {
    326       DEBUG ((EFI_D_ERROR, "DebugAgent: Input parameter Context cannot be NULL!\n"));
    327       CpuDeadLoop ();
    328     } else {
    329       Ia32Idtr =  (IA32_DESCRIPTOR *) Context;
    330       Ia32IdtEntry = (IA32_IDT_ENTRY *)(Ia32Idtr->Base);
    331       MailboxLocation = (UINT64 *) (UINTN) (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow +
    332                                   (UINT32) (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16));
    333       mMailboxPointer = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
    334       VerifyMailboxChecksum (mMailboxPointer);
    335       //
    336       // Get original IDT address and size.
    337       //
    338       AsmReadIdtr ((IA32_DESCRIPTOR *) &Idtr);
    339       IdtEntryCount = (UINT16) ((Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR));
    340       if (IdtEntryCount < 33) {
    341         Idtr.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33 - 1);
    342         Idtr.Base  = (UINTN) &mIdtEntryTable;
    343         ZeroMem (&mIdtEntryTable, Idtr.Limit + 1);
    344         AsmWriteIdtr ((IA32_DESCRIPTOR *) &Idtr);
    345       }
    346 
    347       InitializeDebugIdt ();
    348       //
    349       // Initialize Debug Timer hardware and save its frequency
    350       //
    351       InitializeDebugTimer (&DebugTimerFrequency, TRUE);
    352       UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency);
    353       //
    354       // Enable Debug Timer interrupt and CPU interrupt
    355       //
    356       SaveAndSetDebugTimerInterrupt (TRUE);
    357       EnableInterrupts ();
    358 
    359       FindAndReportModuleImageInfo (SIZE_4KB);
    360     }
    361     break;
    362 
    363   default:
    364     //
    365     // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this
    366     // Debug Agent library instance.
    367     //
    368     DEBUG ((EFI_D_ERROR, "Debug Agent: The InitFlag value is not allowed!\n"));
    369     CpuDeadLoop ();
    370     break;
    371   }
    372 }
    373 
    374