Home | History | Annotate | Download | only in SecPeiDebugAgent
      1 /** @file
      2   SEC Core Debug Agent Library instance 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 "SecPeiDebugAgentLib.h"
     16 
     17 GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN  mSkipBreakpoint = FALSE;
     18 
     19 
     20 GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_VECTOR_HANDOFF_INFO_PPI mVectorHandoffInfoPpi = {
     21   &mVectorHandoffInfoDebugAgent[0]
     22 };
     23 
     24 //
     25 // Ppis to be installed
     26 //
     27 GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_PPI_DESCRIPTOR           mVectorHandoffInfoPpiList[] = {
     28   {
     29     (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
     30     &gEfiVectorHandoffInfoPpiGuid,
     31     &mVectorHandoffInfoPpi
     32   }
     33 };
     34 
     35 GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_NOTIFY_DESCRIPTOR mMemoryDiscoveredNotifyList[1] = {
     36   {
     37     (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
     38     &gEfiPeiMemoryDiscoveredPpiGuid,
     39     DebugAgentCallbackMemoryDiscoveredPpi
     40   }
     41 };
     42 
     43 /**
     44   Check if debug agent support multi-processor.
     45 
     46   @retval TRUE    Multi-processor is supported.
     47   @retval FALSE   Multi-processor is not supported.
     48 
     49 **/
     50 BOOLEAN
     51 MultiProcessorDebugSupport (
     52   VOID
     53   )
     54 {
     55   return FALSE;
     56 }
     57 
     58 /**
     59   Read the Attach/Break-in symbols from the debug port.
     60 
     61   @param[in]  Handle         Pointer to Debug Port handle.
     62   @param[out] BreakSymbol    Returned break symbol.
     63 
     64   @retval EFI_SUCCESS        Read the symbol in BreakSymbol.
     65   @retval EFI_NOT_FOUND      No read the break symbol.
     66 
     67 **/
     68 EFI_STATUS
     69 DebugReadBreakSymbol (
     70   IN  DEBUG_PORT_HANDLE      Handle,
     71   OUT UINT8                  *BreakSymbol
     72   )
     73 {
     74   EFI_STATUS                 Status;
     75   DEBUG_PACKET_HEADER        DebugHeader;
     76   UINT8                      *Data8;
     77 
     78   *BreakSymbol = 0;
     79   //
     80   // If Debug Port buffer has data, read it till it was break symbol or Debug Port buffer empty.
     81   //
     82   Data8 = (UINT8 *) &DebugHeader;
     83   while (TRUE) {
     84     //
     85     // If start symbol is not received
     86     //
     87     if (!DebugPortPollBuffer (Handle)) {
     88       //
     89       // If no data in Debug Port, exit
     90       //
     91       break;
     92     }
     93     //
     94     // Try to read the start symbol
     95     //
     96     DebugAgentReadBuffer (Handle, Data8, 1, 0);
     97     if (*Data8 == DEBUG_STARTING_SYMBOL_ATTACH) {
     98       *BreakSymbol = *Data8;
     99       DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Debug Timer attach symbol received %x", *BreakSymbol);
    100       return EFI_SUCCESS;
    101     }
    102     if (*Data8 == DEBUG_STARTING_SYMBOL_NORMAL) {
    103       Status = ReadRemainingBreakPacket (Handle, &DebugHeader);
    104       if (Status == EFI_SUCCESS) {
    105         *BreakSymbol = DebugHeader.Command;
    106         DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Debug Timer break symbol received %x", *BreakSymbol);
    107         return EFI_SUCCESS;
    108       }
    109       if (Status == EFI_TIMEOUT) {
    110         break;
    111       }
    112     }
    113   }
    114 
    115   return EFI_NOT_FOUND;
    116 }
    117 
    118 /**
    119   Get the pointer to location saved Mailbox pointer from IDT entry.
    120 
    121 **/
    122 VOID *
    123 GetLocationSavedMailboxPointerInIdtEntry (
    124   VOID
    125   )
    126 {
    127   UINTN                     *MailboxLocation;
    128 
    129   MailboxLocation = (UINTN *) GetExceptionHandlerInIdtEntry (DEBUG_MAILBOX_VECTOR);
    130   //
    131   // *MailboxLocation is the pointer to Mailbox
    132   //
    133   VerifyMailboxChecksum ((DEBUG_AGENT_MAILBOX *) (*MailboxLocation));
    134   return MailboxLocation;
    135 }
    136 
    137 /**
    138   Set the pointer of Mailbox into IDT entry before memory is ready.
    139 
    140   @param[in]  MailboxLocation    Pointer to location saved Mailbox pointer.
    141 
    142 **/
    143 VOID
    144 SetLocationSavedMailboxPointerInIdtEntry (
    145   IN VOID                  *MailboxLocation
    146   )
    147 {
    148   SetExceptionHandlerInIdtEntry (DEBUG_MAILBOX_VECTOR, MailboxLocation);
    149 }
    150 
    151 /**
    152   Get the location of Mailbox pointer from the GUIDed HOB.
    153 
    154   @return Pointer to the location saved Mailbox pointer.
    155 
    156 **/
    157 UINT64 *
    158 GetMailboxLocationFromHob (
    159   VOID
    160   )
    161 {
    162   EFI_HOB_GUID_TYPE        *GuidHob;
    163 
    164   GuidHob = GetFirstGuidHob (&gEfiDebugAgentGuid);
    165   if (GuidHob == NULL) {
    166     return NULL;
    167   }
    168   return (UINT64 *) (GET_GUID_HOB_DATA(GuidHob));
    169 }
    170 
    171 /**
    172   Get Debug Agent Mailbox pointer.
    173 
    174   @return Mailbox pointer.
    175 
    176 **/
    177 DEBUG_AGENT_MAILBOX *
    178 GetMailboxPointer (
    179   VOID
    180   )
    181 {
    182   UINT64               DebugPortHandle;
    183   UINT64               *MailboxLocationInIdt;
    184   UINT64               *MailboxLocationInHob;
    185   DEBUG_AGENT_MAILBOX  *Mailbox;
    186 
    187   //
    188   // Get mailbox from IDT entry firstly
    189   //
    190   MailboxLocationInIdt = GetLocationSavedMailboxPointerInIdtEntry ();
    191   Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocationInIdt);
    192   //
    193   // Cannot used GetDebugFlag() to get Debug Flag to avoid GetMailboxPointer() nested
    194   //
    195   if (Mailbox->DebugFlag.Bits.CheckMailboxInHob != 1 ||
    196       Mailbox->DebugFlag.Bits.InitArch != DEBUG_ARCH_SYMBOL) {
    197     //
    198     // If mailbox was setup in SEC or the current CPU arch is different from the init arch
    199     // Debug Agent initialized, return the mailbox from IDT entry directly.
    200     // Otherwise, we need to check the mailbox location saved in GUIDed HOB further.
    201     //
    202     return Mailbox;
    203   }
    204 
    205   MailboxLocationInHob = GetMailboxLocationFromHob ();
    206   //
    207   // Compare mailbox in IDT enry with mailbox in HOB,
    208   // need to fix mailbox location if HOB moved by PEI CORE
    209   //
    210   if (MailboxLocationInHob != MailboxLocationInIdt && MailboxLocationInHob != NULL) {
    211     Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocationInHob);
    212     //
    213     // Fix up Debug Port handler and save new mailbox in IDT entry
    214     //
    215     Mailbox = (DEBUG_AGENT_MAILBOX *)((UINTN)Mailbox + ((UINTN)(MailboxLocationInHob) - (UINTN)MailboxLocationInIdt));
    216     DebugPortHandle = (UINT64)((UINTN)Mailbox->DebugPortHandle + ((UINTN)(MailboxLocationInHob) - (UINTN)MailboxLocationInIdt));
    217     UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
    218     *MailboxLocationInHob = (UINT64)(UINTN)Mailbox;
    219     SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationInHob);
    220     //
    221     // Clean CheckMailboxInHob flag
    222     //
    223     Mailbox->DebugFlag.Bits.CheckMailboxInHob = 0;
    224     UpdateMailboxChecksum (Mailbox);
    225   }
    226 
    227   return Mailbox;
    228 }
    229 
    230 /**
    231   Get debug port handle.
    232 
    233   @return Debug port handle.
    234 
    235 **/
    236 DEBUG_PORT_HANDLE
    237 GetDebugPortHandle (
    238   VOID
    239   )
    240 {
    241   DEBUG_AGENT_MAILBOX    *DebugAgentMailbox;
    242 
    243   DebugAgentMailbox = GetMailboxPointer ();
    244 
    245   return (DEBUG_PORT_HANDLE) (UINTN)(DebugAgentMailbox->DebugPortHandle);
    246 }
    247 
    248 /**
    249   Debug Agent provided notify callback function on Memory Discovered PPI.
    250 
    251   @param[in] PeiServices      Indirect reference to the PEI Services Table.
    252   @param[in] NotifyDescriptor Address of the notification descriptor data structure.
    253   @param[in] Ppi              Address of the PPI that was installed.
    254 
    255   @retval EFI_SUCCESS If the function completed successfully.
    256 
    257 **/
    258 EFI_STATUS
    259 EFIAPI
    260 DebugAgentCallbackMemoryDiscoveredPpi (
    261   IN EFI_PEI_SERVICES                     **PeiServices,
    262   IN EFI_PEI_NOTIFY_DESCRIPTOR            *NotifyDescriptor,
    263   IN VOID                                 *Ppi
    264   )
    265 {
    266   EFI_STATUS                     Status;
    267   DEBUG_AGENT_MAILBOX            *Mailbox;
    268   BOOLEAN                        InterruptStatus;
    269   EFI_PHYSICAL_ADDRESS           Address;
    270   DEBUG_AGENT_MAILBOX            *NewMailbox;
    271   UINT64                         *MailboxLocationInHob;
    272 
    273   //
    274   // Save and disable original interrupt status
    275   //
    276   InterruptStatus = SaveAndDisableInterrupts ();
    277 
    278   //
    279   // Allocate ACPI NVS memory for new Mailbox and Debug Port Handle buffer
    280   //
    281   Status = PeiServicesAllocatePages (
    282              EfiACPIMemoryNVS,
    283              EFI_SIZE_TO_PAGES (sizeof(DEBUG_AGENT_MAILBOX) + PcdGet16(PcdDebugPortHandleBufferSize)),
    284              &Address
    285              );
    286   ASSERT_EFI_ERROR (Status);
    287   NewMailbox = (DEBUG_AGENT_MAILBOX *) (UINTN) Address;
    288   //
    289   // Copy Mailbox and Debug Port Handle buffer to new location in ACPI NVS memory, because original Mailbox
    290   // and Debug Port Handle buffer in the allocated pool that may be marked as free by DXE Core after DXE Core
    291   // reallocates the HOB.
    292   //
    293   Mailbox = GetMailboxPointer ();
    294   CopyMem (NewMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
    295   CopyMem (NewMailbox + 1, (VOID *)(UINTN)Mailbox->DebugPortHandle, PcdGet16(PcdDebugPortHandleBufferSize));
    296   //
    297   // Update Mailbox Location pointer in GUIDed HOB and IDT entry with new one
    298   //
    299   MailboxLocationInHob = GetMailboxLocationFromHob ();
    300   ASSERT (MailboxLocationInHob != NULL);
    301   *MailboxLocationInHob = (UINT64)(UINTN)NewMailbox;
    302   SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationInHob);
    303   //
    304   // Update Debug Port Handle in new Mailbox
    305   //
    306   UpdateMailboxContent (NewMailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, (UINT64)(UINTN)(NewMailbox + 1));
    307   //
    308   // Set physical memory ready flag
    309   //
    310   SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
    311 
    312   if (IsHostAttached ()) {
    313     //
    314     // Trigger one software interrupt to inform HOST
    315     //
    316     TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
    317   }
    318 
    319   //
    320   // Restore interrupt state.
    321   //
    322   SetInterruptState (InterruptStatus);
    323 
    324   return EFI_SUCCESS;
    325 }
    326 
    327 /**
    328   Initialize debug agent.
    329 
    330   This function is used to set up debug environment for SEC and PEI phase.
    331 
    332   If InitFlag is DEBUG_AGENT_INIT_PREMEM_SEC, it will overirde IDT table entries
    333   and initialize debug port. It will enable interrupt to support break-in feature.
    334   It will set up debug agent Mailbox in cache-as-ramfrom. It will be called before
    335   physical memory is ready.
    336   If InitFlag is DEBUG_AGENT_INIT_POSTMEM_SEC, debug agent will build one GUIDed
    337   HOB to copy debug agent Mailbox. It will be called after physical memory is ready.
    338 
    339   This function is used to set up debug environment to support source level debugging.
    340   If certain Debug Agent Library instance has to save some private data in the stack,
    341   this function must work on the mode that doesn't return to the caller, then
    342   the caller needs to wrap up all rest of logic after InitializeDebugAgent() into one
    343   function and pass it into InitializeDebugAgent(). InitializeDebugAgent() is
    344   responsible to invoke the passing-in function at the end of InitializeDebugAgent().
    345 
    346   If the parameter Function is not NULL, Debug Agent Libary instance will invoke it by
    347   passing in the Context to be its parameter.
    348 
    349   If Function() is NULL, Debug Agent Library instance will return after setup debug
    350   environment.
    351 
    352   @param[in] InitFlag     Init flag is used to decide the initialize process.
    353   @param[in] Context      Context needed according to InitFlag; it was optional.
    354   @param[in] Function     Continue function called by debug agent library; it was
    355                           optional.
    356 
    357 **/
    358 VOID
    359 EFIAPI
    360 InitializeDebugAgent (
    361   IN UINT32                InitFlag,
    362   IN VOID                  *Context, OPTIONAL
    363   IN DEBUG_AGENT_CONTINUE  Function  OPTIONAL
    364   )
    365 {
    366   DEBUG_AGENT_MAILBOX              *Mailbox;
    367   DEBUG_AGENT_MAILBOX              *NewMailbox;
    368   DEBUG_AGENT_MAILBOX              MailboxInStack;
    369   DEBUG_AGENT_PHASE2_CONTEXT       Phase2Context;
    370   DEBUG_AGENT_CONTEXT_POSTMEM_SEC  *DebugAgentContext;
    371   EFI_STATUS                       Status;
    372   IA32_DESCRIPTOR                  *Ia32Idtr;
    373   IA32_IDT_ENTRY                   *Ia32IdtEntry;
    374   UINT64                           DebugPortHandle;
    375   UINT64                           MailboxLocation;
    376   UINT64                           *MailboxLocationPointer;
    377   EFI_PHYSICAL_ADDRESS             Address;
    378   UINT32                           DebugTimerFrequency;
    379   BOOLEAN                          CpuInterruptState;
    380 
    381   //
    382   // Disable interrupts and save current interrupt state
    383   //
    384   CpuInterruptState = SaveAndDisableInterrupts();
    385 
    386   switch (InitFlag) {
    387 
    388   case DEBUG_AGENT_INIT_PREMEM_SEC:
    389 
    390     InitializeDebugIdt ();
    391 
    392     MailboxLocation = (UINT64)(UINTN)&MailboxInStack;
    393     Mailbox = &MailboxInStack;
    394     ZeroMem ((VOID *) Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
    395     //
    396     // Get and save debug port handle and set the length of memory block.
    397     //
    398     SetLocationSavedMailboxPointerInIdtEntry (&MailboxLocation);
    399     //
    400     // Force error message could be printed during the first shakehand between Target/HOST.
    401     //
    402     SetDebugFlag (DEBUG_AGENT_FLAG_PRINT_ERROR_LEVEL, DEBUG_AGENT_ERROR);
    403     //
    404     // Save init arch type when debug agent initialized
    405     //
    406     SetDebugFlag (DEBUG_AGENT_FLAG_INIT_ARCH, DEBUG_ARCH_SYMBOL);
    407     //
    408     // Initialize Debug Timer hardware and save its frequency
    409     //
    410     InitializeDebugTimer (&DebugTimerFrequency, TRUE);
    411     UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency);
    412 
    413     Phase2Context.InitFlag = InitFlag;
    414     Phase2Context.Context  = Context;
    415     Phase2Context.Function = Function;
    416     DebugPortInitialize ((VOID *) &Phase2Context, InitializeDebugAgentPhase2);
    417     //
    418     // If reaches here, it means Debug Port initialization failed.
    419     //
    420     DEBUG ((EFI_D_ERROR, "Debug Agent: Debug port initialization failed.\n"));
    421 
    422     break;
    423 
    424   case DEBUG_AGENT_INIT_POSTMEM_SEC:
    425     Mailbox = GetMailboxPointer ();
    426     //
    427     // Memory has been ready
    428     //
    429     SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
    430     if (IsHostAttached ()) {
    431       //
    432       // Trigger one software interrupt to inform HOST
    433       //
    434       TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
    435     }
    436     //
    437     // Install Vector Handoff Info PPI to persist vectors used by Debug Agent
    438     //
    439     Status = PeiServicesInstallPpi (&mVectorHandoffInfoPpiList[0]);
    440     if (EFI_ERROR (Status)) {
    441       DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to install Vector Handoff Info PPI!\n"));
    442       CpuDeadLoop ();
    443     }
    444     //
    445     // Fix up Debug Port handle address and mailbox address
    446     //
    447     DebugAgentContext = (DEBUG_AGENT_CONTEXT_POSTMEM_SEC *) Context;
    448     if (DebugAgentContext != NULL) {
    449       DebugPortHandle = (UINT64)(UINT32)(Mailbox->DebugPortHandle + DebugAgentContext->StackMigrateOffset);
    450       UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
    451       Mailbox = (DEBUG_AGENT_MAILBOX *) ((UINTN) Mailbox + DebugAgentContext->StackMigrateOffset);
    452       MailboxLocation = (UINT64)(UINTN)Mailbox;
    453       //
    454       // Build mailbox location in HOB and fix-up its address
    455       //
    456       MailboxLocationPointer = BuildGuidDataHob (
    457                                  &gEfiDebugAgentGuid,
    458                                  &MailboxLocation,
    459                                  sizeof (UINT64)
    460                                  );
    461       MailboxLocationPointer = (UINT64 *) ((UINTN) MailboxLocationPointer + DebugAgentContext->HeapMigrateOffset);
    462     } else {
    463       //
    464       // DebugAgentContext is NULL. Then, Mailbox can directly be copied into memory.
    465       // Allocate ACPI NVS memory for new Mailbox and Debug Port Handle buffer
    466       //
    467       Status = PeiServicesAllocatePages (
    468                  EfiACPIMemoryNVS,
    469                  EFI_SIZE_TO_PAGES (sizeof(DEBUG_AGENT_MAILBOX) + PcdGet16(PcdDebugPortHandleBufferSize)),
    470                  &Address
    471                  );
    472       if (EFI_ERROR (Status)) {
    473         DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to allocate pages!\n"));
    474         CpuDeadLoop ();
    475       }
    476       NewMailbox = (DEBUG_AGENT_MAILBOX *) (UINTN) Address;
    477       //
    478       // Copy Mailbox and Debug Port Handle buffer to new location in ACPI NVS memory, because original Mailbox
    479       // and Debug Port Handle buffer in the allocated pool that may be marked as free by DXE Core after DXE Core
    480       // reallocates the HOB.
    481       //
    482       CopyMem (NewMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
    483       CopyMem (NewMailbox + 1, (VOID *)(UINTN)Mailbox->DebugPortHandle, PcdGet16(PcdDebugPortHandleBufferSize));
    484       UpdateMailboxContent (NewMailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, (UINT64)(UINTN)(NewMailbox + 1));
    485       MailboxLocation = (UINT64)(UINTN)NewMailbox;
    486       //
    487       // Build mailbox location in HOB
    488       //
    489       MailboxLocationPointer = BuildGuidDataHob (
    490                                  &gEfiDebugAgentGuid,
    491                                  &MailboxLocation,
    492                                  sizeof (UINT64)
    493                                  );
    494     }
    495     //
    496     // Update IDT entry to save the location saved mailbox pointer
    497     //
    498     SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer);
    499     break;
    500 
    501   case DEBUG_AGENT_INIT_PEI:
    502     if (Context == NULL) {
    503       DEBUG ((EFI_D_ERROR, "DebugAgent: Input parameter Context cannot be NULL!\n"));
    504       CpuDeadLoop ();
    505     }
    506     //
    507     // Check if Debug Agent has initialized before
    508     //
    509     if (IsDebugAgentInitialzed()) {
    510       DEBUG ((EFI_D_WARN, "Debug Agent: It has already initialized in SEC Core!\n"));
    511       break;
    512     }
    513     //
    514     // Install Vector Handoff Info PPI to persist vectors used by Debug Agent
    515     //
    516     Status = PeiServicesInstallPpi (&mVectorHandoffInfoPpiList[0]);
    517     if (EFI_ERROR (Status)) {
    518       DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to install Vector Handoff Info PPI!\n"));
    519       CpuDeadLoop ();
    520     }
    521     //
    522     // Set up IDT entries
    523     //
    524     InitializeDebugIdt ();
    525     //
    526     // Build mailbox in HOB and setup Mailbox Set In Pei flag
    527     //
    528     Mailbox = AllocateZeroPool (sizeof (DEBUG_AGENT_MAILBOX));
    529     if (Mailbox == NULL) {
    530       DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to allocate memory!\n"));
    531       CpuDeadLoop ();
    532     } else {
    533       MailboxLocation = (UINT64)(UINTN)Mailbox;
    534       MailboxLocationPointer = BuildGuidDataHob (
    535                                  &gEfiDebugAgentGuid,
    536                                  &MailboxLocation,
    537                                  sizeof (UINT64)
    538                                  );
    539       //
    540       // Initialize Debug Timer hardware and save its frequency
    541       //
    542       InitializeDebugTimer (&DebugTimerFrequency, TRUE);
    543       UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency);
    544       //
    545       // Update IDT entry to save the location pointer saved mailbox pointer
    546       //
    547       SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer);
    548     }
    549     //
    550     // Save init arch type when debug agent initialized
    551     //
    552     SetDebugFlag (DEBUG_AGENT_FLAG_INIT_ARCH, DEBUG_ARCH_SYMBOL);
    553     //
    554     // Register for a callback once memory has been initialized.
    555     // If memery has been ready, the callback funtion will be invoked immediately
    556     //
    557     Status = PeiServicesNotifyPpi (&mMemoryDiscoveredNotifyList[0]);
    558     if (EFI_ERROR (Status)) {
    559       DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to register memory discovered callback function!\n"));
    560       CpuDeadLoop ();
    561     }
    562     //
    563     // Set HOB check flag if memory has not been ready yet
    564     //
    565     if (GetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY) == 0) {
    566       SetDebugFlag (DEBUG_AGENT_FLAG_CHECK_MAILBOX_IN_HOB, 1);
    567     }
    568 
    569     Phase2Context.InitFlag = InitFlag;
    570     Phase2Context.Context  = Context;
    571     Phase2Context.Function = Function;
    572     DebugPortInitialize ((VOID *) &Phase2Context, InitializeDebugAgentPhase2);
    573 
    574     FindAndReportModuleImageInfo (4);
    575 
    576     break;
    577 
    578   case DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64:
    579     if (Context == NULL) {
    580       DEBUG ((EFI_D_ERROR, "DebugAgent: Input parameter Context cannot be NULL!\n"));
    581       CpuDeadLoop ();
    582     } else {
    583       Ia32Idtr =  (IA32_DESCRIPTOR *) Context;
    584       Ia32IdtEntry = (IA32_IDT_ENTRY *)(Ia32Idtr->Base);
    585       MailboxLocationPointer = (UINT64 *) (UINTN) (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow +
    586                                          (UINT32) (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16));
    587       Mailbox = (DEBUG_AGENT_MAILBOX *) (UINTN)(*MailboxLocationPointer);
    588       //
    589       // Mailbox should valid and setup before executing thunk code
    590       //
    591       VerifyMailboxChecksum (Mailbox);
    592 
    593       DebugPortHandle = (UINT64) (UINTN)DebugPortInitialize ((VOID *)(UINTN)Mailbox->DebugPortHandle, NULL);
    594       UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
    595       //
    596       // Set up IDT entries
    597       //
    598       InitializeDebugIdt ();
    599       //
    600       // Update IDT entry to save location pointer saved the mailbox pointer
    601       //
    602       SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer);
    603 
    604       FindAndReportModuleImageInfo (4);
    605     }
    606     break;
    607 
    608   default:
    609     //
    610     // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this
    611     // Debug Agent library instance.
    612     //
    613     DEBUG ((EFI_D_ERROR, "Debug Agent: The InitFlag value is not allowed!\n"));
    614     CpuDeadLoop ();
    615     break;
    616   }
    617 
    618   if (InitFlag == DEBUG_AGENT_INIT_POSTMEM_SEC) {
    619     //
    620     // Restore CPU Interrupt state and keep debug timer interrupt state as is
    621     // in DEBUG_AGENT_INIT_POSTMEM_SEC case
    622     //
    623     SetInterruptState (CpuInterruptState);
    624   } else {
    625     //
    626     // Enable Debug Timer interrupt
    627     //
    628     SaveAndSetDebugTimerInterrupt (TRUE);
    629     //
    630     // Enable CPU interrupts so debug timer interrupts can be delivered
    631     //
    632     EnableInterrupts ();
    633   }
    634   //
    635   // If Function is not NULL, invoke it always whatever debug agent was initialized sucesssfully or not.
    636   //
    637   if (Function != NULL) {
    638     Function (Context);
    639   }
    640   //
    641   // Set return status for DEBUG_AGENT_INIT_PEI
    642   //
    643   if (InitFlag == DEBUG_AGENT_INIT_PEI && Context != NULL) {
    644     *(EFI_STATUS *)Context = EFI_SUCCESS;
    645   }
    646 }
    647 
    648 /**
    649   Caller provided function to be invoked at the end of DebugPortInitialize().
    650 
    651   Refer to the descrption for DebugPortInitialize() for more details.
    652 
    653   @param[in] Context           The first input argument of DebugPortInitialize().
    654   @param[in] DebugPortHandle   Debug port handle created by Debug Communication Libary.
    655 
    656 **/
    657 VOID
    658 EFIAPI
    659 InitializeDebugAgentPhase2 (
    660   IN VOID                  *Context,
    661   IN DEBUG_PORT_HANDLE     DebugPortHandle
    662   )
    663 {
    664   DEBUG_AGENT_PHASE2_CONTEXT *Phase2Context;
    665   UINT64                     *MailboxLocation;
    666   DEBUG_AGENT_MAILBOX        *Mailbox;
    667   EFI_SEC_PEI_HAND_OFF       *SecCoreData;
    668   UINT16                     BufferSize;
    669   UINT64                     NewDebugPortHandle;
    670 
    671   Phase2Context = (DEBUG_AGENT_PHASE2_CONTEXT *) Context;
    672   MailboxLocation = GetLocationSavedMailboxPointerInIdtEntry ();
    673   Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
    674   BufferSize = PcdGet16(PcdDebugPortHandleBufferSize);
    675   if (Phase2Context->InitFlag == DEBUG_AGENT_INIT_PEI && BufferSize != 0) {
    676     NewDebugPortHandle = (UINT64)(UINTN)AllocateCopyPool (BufferSize, DebugPortHandle);
    677   } else {
    678     NewDebugPortHandle = (UINT64)(UINTN)DebugPortHandle;
    679   }
    680   UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, NewDebugPortHandle);
    681 
    682   //
    683   // Trigger one software interrupt to inform HOST
    684   //
    685   TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE);
    686 
    687   if (Phase2Context->InitFlag == DEBUG_AGENT_INIT_PREMEM_SEC) {
    688     //
    689     // If Temporary RAM region is below 128 MB, then send message to
    690     // host to disable low memory filtering.
    691     //
    692     SecCoreData = (EFI_SEC_PEI_HAND_OFF *)Phase2Context->Context;
    693     if ((UINTN)SecCoreData->TemporaryRamBase < BASE_128MB && IsHostAttached ()) {
    694       SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
    695       TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
    696     }
    697     //
    698     // Enable Debug Timer interrupt
    699     //
    700     SaveAndSetDebugTimerInterrupt (TRUE);
    701     //
    702     // Enable CPU interrupts so debug timer interrupts can be delivered
    703     //
    704     EnableInterrupts ();
    705     //
    706     // Call continuation function if it is not NULL.
    707     //
    708     Phase2Context->Function (Phase2Context->Context);
    709   }
    710 }
    711