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