mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-10-28 00:04:17 +00:00 
			
		
		
		
	 a1ac5791ff
			
		
	
	
		a1ac5791ff
		
	
	
	
	
		
			
			Signed-off-by: Jeff Fan <jeff.fan@intel.com> Reviewed-by: Ruiyu Ni <ruiyu.ni@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@14979 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			680 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			680 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   SEC Core Debug Agent Library instance implementition.
 | |
| 
 | |
|   Copyright (c) 2010 - 2013, Intel Corporation. All rights reserved.<BR>
 | |
|   This program and the accompanying materials
 | |
|   are licensed and made available under the terms and conditions of the BSD License
 | |
|   which accompanies this distribution.  The full text of the license may be found at
 | |
|   http://opensource.org/licenses/bsd-license.php.
 | |
| 
 | |
|   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
|   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "SecPeiDebugAgentLib.h"
 | |
| 
 | |
| BOOLEAN  mSkipBreakpoint = FALSE;
 | |
| 
 | |
| 
 | |
| EFI_PEI_VECTOR_HANDOFF_INFO_PPI mVectorHandoffInfoPpi = {
 | |
|   &mVectorHandoffInfoDebugAgent[0]
 | |
| };
 | |
| 
 | |
| //
 | |
| // Ppis to be installed
 | |
| //
 | |
| EFI_PEI_PPI_DESCRIPTOR           mVectorHandoffInfoPpiList[] = { 
 | |
|   {
 | |
|     (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
 | |
|     &gEfiVectorHandoffInfoPpiGuid,
 | |
|     &mVectorHandoffInfoPpi
 | |
|   }
 | |
| };
 | |
| 
 | |
| EFI_PEI_NOTIFY_DESCRIPTOR mMemoryDiscoveredNotifyList[1] = {
 | |
|   {
 | |
|     (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
 | |
|     &gEfiPeiMemoryDiscoveredPpiGuid,
 | |
|     DebugAgentCallbackMemoryDiscoveredPpi
 | |
|   }
 | |
| };
 | |
| 
 | |
| /**
 | |
|   Check if debug agent support multi-processor.
 | |
| 
 | |
|   @retval TRUE    Multi-processor is supported.
 | |
|   @retval FALSE   Multi-processor is not supported.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| MultiProcessorDebugSupport (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Read the Attach/Break-in symbols from the debug port.
 | |
| 
 | |
|   @param[in]  Handle         Pointer to Debug Port handle.
 | |
|   @param[out] BreakSymbol    Returned break symbol.
 | |
| 
 | |
|   @retval EFI_SUCCESS        Read the symbol in BreakSymbol.
 | |
|   @retval EFI_NOT_FOUND      No read the break symbol.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| DebugReadBreakSymbol (
 | |
|   IN  DEBUG_PORT_HANDLE      Handle,
 | |
|   OUT UINT8                  *BreakSymbol
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                 Status;
 | |
|   DEBUG_PACKET_HEADER        DebugHeader;
 | |
|   UINT8                      *Data8;
 | |
| 
 | |
|   *BreakSymbol = 0;
 | |
|   //
 | |
|   // If Debug Port buffer has data, read it till it was break symbol or Debug Port buffer empty.
 | |
|   //
 | |
|   Data8 = (UINT8 *) &DebugHeader;
 | |
|   while (TRUE) {
 | |
|     //
 | |
|     // If start symbol is not received
 | |
|     //
 | |
|     if (!DebugPortPollBuffer (Handle)) {
 | |
|       //
 | |
|       // If no data in Debug Port, exit
 | |
|       //
 | |
|       break;
 | |
|     }
 | |
|     //
 | |
|     // Try to read the start symbol
 | |
|     //
 | |
|     DebugPortReadBuffer (Handle, Data8, 1, 0);
 | |
|     if (*Data8 == DEBUG_STARTING_SYMBOL_ATTACH) {
 | |
|       *BreakSymbol = *Data8;
 | |
|       DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Debug Timer attach symbol received %x", *BreakSymbol);
 | |
|       return EFI_SUCCESS;
 | |
|     } 
 | |
|     if (*Data8 == DEBUG_STARTING_SYMBOL_NORMAL) {
 | |
|       Status = ReadRemainingBreakPacket (Handle, &DebugHeader);
 | |
|       if (Status == EFI_SUCCESS) {
 | |
|         *BreakSymbol = DebugHeader.Command;
 | |
|         DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Debug Timer break symbol received %x", *BreakSymbol);
 | |
|         return EFI_SUCCESS;
 | |
|       }
 | |
|       if (Status == EFI_TIMEOUT) {
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   
 | |
|   return EFI_NOT_FOUND;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get the pointer to location saved Mailbox pointer from IDT entry.
 | |
| 
 | |
| **/
 | |
| VOID *
 | |
| GetLocationSavedMailboxPointerInIdtEntry (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   UINTN                     *MailboxLocation;
 | |
| 
 | |
|   MailboxLocation = (UINTN *) GetExceptionHandlerInIdtEntry (DEBUG_MAILBOX_VECTOR);
 | |
|   //
 | |
|   // *MailboxLocation is the pointer to Mailbox
 | |
|   //
 | |
|   VerifyMailboxChecksum ((DEBUG_AGENT_MAILBOX *) (*MailboxLocation));
 | |
|   return MailboxLocation;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Set the pointer of Mailbox into IDT entry before memory is ready.
 | |
| 
 | |
|   @param[in]  MailboxLocation    Pointer to location saved Mailbox pointer.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| SetLocationSavedMailboxPointerInIdtEntry (
 | |
|   IN VOID                  *MailboxLocation
 | |
|   )
 | |
| {
 | |
|   SetExceptionHandlerInIdtEntry (DEBUG_MAILBOX_VECTOR, MailboxLocation);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get the location of Mailbox pointer from the GUIDed HOB.
 | |
| 
 | |
|   @return Pointer to the location saved Mailbox pointer.
 | |
| 
 | |
| **/
 | |
| UINT64 *
 | |
| GetMailboxLocationFromHob (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   EFI_HOB_GUID_TYPE        *GuidHob;
 | |
| 
 | |
|   GuidHob = GetFirstGuidHob (&gEfiDebugAgentGuid);
 | |
|   if (GuidHob == NULL) {
 | |
|     return NULL;
 | |
|   }
 | |
|   return (UINT64 *) (GET_GUID_HOB_DATA(GuidHob));
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get Debug Agent Mailbox pointer.
 | |
| 
 | |
|   @return Mailbox pointer.
 | |
| 
 | |
| **/
 | |
| DEBUG_AGENT_MAILBOX *
 | |
| GetMailboxPointer (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   UINT64               DebugPortHandle;
 | |
|   UINT64               *MailboxLocationInIdt;
 | |
|   UINT64               *MailboxLocationInHob;
 | |
|   DEBUG_AGENT_MAILBOX  *Mailbox;
 | |
|   
 | |
|   //
 | |
|   // Get mailbox from IDT entry firstly
 | |
|   //
 | |
|   MailboxLocationInIdt = GetLocationSavedMailboxPointerInIdtEntry ();
 | |
|   Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocationInIdt);
 | |
|   //
 | |
|   // Cannot used GetDebugFlag() to get Debug Flag to avoid GetMailboxPointer() nested
 | |
|   //
 | |
|   if (Mailbox->DebugFlag.Bits.CheckMailboxInHob != 1 ||
 | |
|       Mailbox->DebugFlag.Bits.InitArch != DEBUG_ARCH_SYMBOL) {
 | |
|     //
 | |
|     // If mailbox was setup in SEC or the current CPU arch is different from the init arch
 | |
|     // Debug Agent initialized, return the mailbox from IDT entry directly.
 | |
|     // Otherwise, we need to check the mailbox location saved in GUIDed HOB further.
 | |
|     // 
 | |
|     return Mailbox;
 | |
|   }
 | |
| 
 | |
|   MailboxLocationInHob = GetMailboxLocationFromHob ();
 | |
|   //
 | |
|   // Compare mailbox in IDT enry with mailbox in HOB,
 | |
|   // need to fix mailbox location if HOB moved by PEI CORE
 | |
|   //
 | |
|   if (MailboxLocationInHob != MailboxLocationInIdt && MailboxLocationInHob != NULL) {
 | |
|     Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocationInHob);
 | |
|     //
 | |
|     // Fix up Debug Port handler and save new mailbox in IDT entry
 | |
|     //
 | |
|     Mailbox = (DEBUG_AGENT_MAILBOX *)((UINTN)Mailbox + ((UINTN)(MailboxLocationInHob) - (UINTN)MailboxLocationInIdt));
 | |
|     DebugPortHandle = (UINT64)((UINTN)Mailbox->DebugPortHandle + ((UINTN)(MailboxLocationInHob) - (UINTN)MailboxLocationInIdt));
 | |
|     UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
 | |
|     *MailboxLocationInHob = (UINT64)(UINTN)Mailbox;
 | |
|     SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationInHob);
 | |
|     //
 | |
|     // Clean CheckMailboxInHob flag
 | |
|     //
 | |
|     Mailbox->DebugFlag.Bits.CheckMailboxInHob = 0;
 | |
|     UpdateMailboxChecksum (Mailbox);
 | |
|   }
 | |
| 
 | |
|   return Mailbox;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get debug port handle.
 | |
| 
 | |
|   @return Debug port handle.
 | |
| 
 | |
| **/
 | |
| DEBUG_PORT_HANDLE
 | |
| GetDebugPortHandle (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   DEBUG_AGENT_MAILBOX    *DebugAgentMailbox;
 | |
|   
 | |
|   DebugAgentMailbox = GetMailboxPointer ();
 | |
| 
 | |
|   return (DEBUG_PORT_HANDLE) (UINTN)(DebugAgentMailbox->DebugPortHandle);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Debug Agent provided notify callback function on Memory Discovered PPI.
 | |
| 
 | |
|   @param[in] PeiServices      Indirect reference to the PEI Services Table.
 | |
|   @param[in] NotifyDescriptor Address of the notification descriptor data structure.
 | |
|   @param[in] Ppi              Address of the PPI that was installed.
 | |
| 
 | |
|   @retval EFI_SUCCESS If the function completed successfully.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| DebugAgentCallbackMemoryDiscoveredPpi (
 | |
|   IN EFI_PEI_SERVICES                     **PeiServices,
 | |
|   IN EFI_PEI_NOTIFY_DESCRIPTOR            *NotifyDescriptor,
 | |
|   IN VOID                                 *Ppi
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                     Status;
 | |
|   DEBUG_AGENT_MAILBOX            *Mailbox;
 | |
|   BOOLEAN                        InterruptStatus;
 | |
|   EFI_PHYSICAL_ADDRESS           Address; 
 | |
|   DEBUG_AGENT_MAILBOX            *NewMailbox;
 | |
|   UINT64                         *MailboxLocationInHob;
 | |
| 
 | |
|   //
 | |
|   // Save and disable original interrupt status
 | |
|   //
 | |
|   InterruptStatus = SaveAndDisableInterrupts ();
 | |
| 
 | |
|   //
 | |
|   // Allocate ACPI NVS memory for new Mailbox and Debug Port Handle buffer
 | |
|   //
 | |
|   Status = PeiServicesAllocatePages (
 | |
|              EfiACPIMemoryNVS,
 | |
|              EFI_SIZE_TO_PAGES (sizeof(DEBUG_AGENT_MAILBOX) + PcdGet16(PcdDebugPortHandleBufferSize)),
 | |
|              &Address
 | |
|              );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
|   NewMailbox = (DEBUG_AGENT_MAILBOX *) (UINTN) Address;
 | |
|   //
 | |
|   // Copy Mailbox and Debug Port Handle buffer to new location in ACPI NVS memory, because original Mailbox
 | |
|   // and Debug Port Handle buffer in the allocated pool that may be marked as free by DXE Core after DXE Core
 | |
|   // reallocates the HOB.
 | |
|   //
 | |
|   Mailbox = GetMailboxPointer ();
 | |
|   CopyMem (NewMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
 | |
|   CopyMem (NewMailbox + 1, (VOID *)(UINTN)Mailbox->DebugPortHandle, PcdGet16(PcdDebugPortHandleBufferSize));
 | |
|   //
 | |
|   // Update Mailbox Location pointer in GUIDed HOB and IDT entry with new one
 | |
|   //
 | |
|   MailboxLocationInHob = GetMailboxLocationFromHob ();
 | |
|   ASSERT (MailboxLocationInHob != NULL);
 | |
|   *MailboxLocationInHob = (UINT64)(UINTN)NewMailbox;
 | |
|   SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationInHob);
 | |
|   //
 | |
|   // Update Debug Port Handle in new Mailbox
 | |
|   //
 | |
|   UpdateMailboxContent (NewMailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, (UINT64)(UINTN)(NewMailbox + 1));
 | |
|   //
 | |
|   // Set physical memory ready flag
 | |
|   //
 | |
|   SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
 | |
| 
 | |
|   if (IsHostAttached ()) {
 | |
|     //
 | |
|     // Trigger one software interrupt to inform HOST
 | |
|     //
 | |
|     TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Restore interrupt state.
 | |
|   //
 | |
|   SetInterruptState (InterruptStatus);
 | |
|   
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Initialize debug agent.
 | |
| 
 | |
|   This function is used to set up debug environment for SEC and PEI phase.
 | |
| 
 | |
|   If InitFlag is DEBUG_AGENT_INIT_PREMEM_SEC, it will overirde IDT table entries
 | |
|   and initialize debug port. It will enable interrupt to support break-in feature.
 | |
|   It will set up debug agent Mailbox in cache-as-ramfrom. It will be called before
 | |
|   physical memory is ready.
 | |
|   If InitFlag is DEBUG_AGENT_INIT_POSTMEM_SEC, debug agent will build one GUIDed
 | |
|   HOB to copy debug agent Mailbox. It will be called after physical memory is ready.
 | |
| 
 | |
|   This function is used to set up debug environment to support source level debugging.
 | |
|   If certain Debug Agent Library instance has to save some private data in the stack,
 | |
|   this function must work on the mode that doesn't return to the caller, then
 | |
|   the caller needs to wrap up all rest of logic after InitializeDebugAgent() into one
 | |
|   function and pass it into InitializeDebugAgent(). InitializeDebugAgent() is
 | |
|   responsible to invoke the passing-in function at the end of InitializeDebugAgent().
 | |
| 
 | |
|   If the parameter Function is not NULL, Debug Agent Libary instance will invoke it by
 | |
|   passing in the Context to be its parameter.
 | |
| 
 | |
|   If Function() is NULL, Debug Agent Library instance will return after setup debug
 | |
|   environment.
 | |
| 
 | |
|   @param[in] InitFlag     Init flag is used to decide the initialize process.
 | |
|   @param[in] Context      Context needed according to InitFlag; it was optional.
 | |
|   @param[in] Function     Continue function called by debug agent library; it was
 | |
|                           optional.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| InitializeDebugAgent (
 | |
|   IN UINT32                InitFlag,
 | |
|   IN VOID                  *Context, OPTIONAL
 | |
|   IN DEBUG_AGENT_CONTINUE  Function  OPTIONAL
 | |
|   )
 | |
| {
 | |
|   DEBUG_AGENT_MAILBOX              *Mailbox;
 | |
|   DEBUG_AGENT_MAILBOX              *NewMailbox;
 | |
|   DEBUG_AGENT_MAILBOX              MailboxInStack;
 | |
|   DEBUG_AGENT_PHASE2_CONTEXT       Phase2Context;
 | |
|   DEBUG_AGENT_CONTEXT_POSTMEM_SEC  *DebugAgentContext;
 | |
|   EFI_STATUS                       Status;
 | |
|   IA32_DESCRIPTOR                  *Ia32Idtr;
 | |
|   IA32_IDT_ENTRY                   *Ia32IdtEntry;
 | |
|   UINT64                           DebugPortHandle;
 | |
|   UINT64                           MailboxLocation;
 | |
|   UINT64                           *MailboxLocationPointer;
 | |
|   EFI_PHYSICAL_ADDRESS             Address; 
 | |
|   
 | |
|   DisableInterrupts ();
 | |
| 
 | |
|   switch (InitFlag) {
 | |
| 
 | |
|   case DEBUG_AGENT_INIT_PREMEM_SEC:
 | |
| 
 | |
|     InitializeDebugIdt ();
 | |
| 
 | |
|     MailboxLocation = (UINT64)(UINTN)&MailboxInStack;
 | |
|     Mailbox = &MailboxInStack;
 | |
|     ZeroMem ((VOID *) Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
 | |
|     //
 | |
|     // Get and save debug port handle and set the length of memory block.
 | |
|     //
 | |
|     SetLocationSavedMailboxPointerInIdtEntry (&MailboxLocation);
 | |
|     //
 | |
|     // Force error message could be printed during the first shakehand between Target/HOST.
 | |
|     //
 | |
|     SetDebugFlag (DEBUG_AGENT_FLAG_PRINT_ERROR_LEVEL, DEBUG_AGENT_ERROR);
 | |
|     //
 | |
|     // Save init arch type when debug agent initialized
 | |
|     //
 | |
|     SetDebugFlag (DEBUG_AGENT_FLAG_INIT_ARCH, DEBUG_ARCH_SYMBOL);
 | |
| 
 | |
|     InitializeDebugTimer ();
 | |
| 
 | |
|     Phase2Context.InitFlag = InitFlag;
 | |
|     Phase2Context.Context  = Context;
 | |
|     Phase2Context.Function = Function;
 | |
|     DebugPortInitialize ((VOID *) &Phase2Context, InitializeDebugAgentPhase2);
 | |
|     //
 | |
|     // If reaches here, it means Debug Port initialization failed.
 | |
|     //
 | |
|     DEBUG ((EFI_D_ERROR, "Debug Agent: Debug port initialization failed.\n"));
 | |
| 
 | |
|     break;
 | |
| 
 | |
|   case DEBUG_AGENT_INIT_POSTMEM_SEC:
 | |
|     Mailbox = GetMailboxPointer ();
 | |
|     //
 | |
|     // Memory has been ready
 | |
|     //
 | |
|     SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
 | |
|     if (IsHostAttached ()) {
 | |
|       //
 | |
|       // Trigger one software interrupt to inform HOST
 | |
|       //
 | |
|       TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
 | |
|     }
 | |
|     //
 | |
|     // Install Vector Handoff Info PPI to persist vectors used by Debug Agent
 | |
|     //
 | |
|     Status = PeiServicesInstallPpi (&mVectorHandoffInfoPpiList[0]);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to install Vector Handoff Info PPI!\n"));
 | |
|       CpuDeadLoop ();
 | |
|     }
 | |
|     //
 | |
|     // Fix up Debug Port handle address and mailbox address
 | |
|     //
 | |
|     DebugAgentContext = (DEBUG_AGENT_CONTEXT_POSTMEM_SEC *) Context;
 | |
|     if (DebugAgentContext != NULL) {
 | |
|       DebugPortHandle = (UINT64)(UINT32)(Mailbox->DebugPortHandle + DebugAgentContext->StackMigrateOffset);
 | |
|       UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
 | |
|       Mailbox = (DEBUG_AGENT_MAILBOX *) ((UINTN) Mailbox + DebugAgentContext->StackMigrateOffset);
 | |
|       MailboxLocation = (UINT64)(UINTN)Mailbox;
 | |
|       //
 | |
|       // Build mailbox location in HOB and fix-up its address
 | |
|       //
 | |
|       MailboxLocationPointer = BuildGuidDataHob (
 | |
|                                  &gEfiDebugAgentGuid,
 | |
|                                  &MailboxLocation,
 | |
|                                  sizeof (UINT64)
 | |
|                                  );
 | |
|       MailboxLocationPointer = (UINT64 *) ((UINTN) MailboxLocationPointer + DebugAgentContext->HeapMigrateOffset);
 | |
|     } else {
 | |
|       //
 | |
|       // DebugAgentContext is NULL. Then, Mailbox can directly be copied into memory.
 | |
|       // Allocate ACPI NVS memory for new Mailbox and Debug Port Handle buffer
 | |
|       //
 | |
|       Status = PeiServicesAllocatePages (
 | |
|                  EfiACPIMemoryNVS,
 | |
|                  EFI_SIZE_TO_PAGES (sizeof(DEBUG_AGENT_MAILBOX) + PcdGet16(PcdDebugPortHandleBufferSize)),
 | |
|                  &Address
 | |
|                  );
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to allocate pages!\n"));
 | |
|         CpuDeadLoop ();
 | |
|       }
 | |
|       NewMailbox = (DEBUG_AGENT_MAILBOX *) (UINTN) Address;
 | |
|       //
 | |
|       // Copy Mailbox and Debug Port Handle buffer to new location in ACPI NVS memory, because original Mailbox
 | |
|       // and Debug Port Handle buffer in the allocated pool that may be marked as free by DXE Core after DXE Core
 | |
|       // reallocates the HOB.
 | |
|       //
 | |
|       CopyMem (NewMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
 | |
|       CopyMem (NewMailbox + 1, (VOID *)(UINTN)Mailbox->DebugPortHandle, PcdGet16(PcdDebugPortHandleBufferSize));
 | |
|       UpdateMailboxContent (NewMailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, (UINT64)(UINTN)(NewMailbox + 1));
 | |
|       MailboxLocation = (UINT64)(UINTN)NewMailbox;
 | |
|       //
 | |
|       // Build mailbox location in HOB
 | |
|       //
 | |
|       MailboxLocationPointer = BuildGuidDataHob (
 | |
|                                  &gEfiDebugAgentGuid,
 | |
|                                  &MailboxLocation,
 | |
|                                  sizeof (UINT64)
 | |
|                                  );
 | |
|     }
 | |
|     //
 | |
|     // Update IDT entry to save the location saved mailbox pointer
 | |
|     //
 | |
|     SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer);
 | |
|     break;
 | |
| 
 | |
|   case DEBUG_AGENT_INIT_PEI:
 | |
|     if (Context == NULL) {
 | |
|       DEBUG ((EFI_D_ERROR, "DebugAgent: Input parameter Context cannot be NULL!\n"));
 | |
|       CpuDeadLoop ();
 | |
|     }
 | |
|     //
 | |
|     // Check if Debug Agent has initialized before
 | |
|     //
 | |
|     if (IsDebugAgentInitialzed()) {
 | |
|       DEBUG ((EFI_D_WARN, "Debug Agent: It has already initialized in SEC Core!\n"));
 | |
|       break;
 | |
|     }
 | |
|     //
 | |
|     // Install Vector Handoff Info PPI to persist vectors used by Debug Agent
 | |
|     //
 | |
|     Status = PeiServicesInstallPpi (&mVectorHandoffInfoPpiList[0]);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to install Vector Handoff Info PPI!\n"));
 | |
|       CpuDeadLoop ();
 | |
|     }
 | |
|     //
 | |
|     // Set up IDT entries
 | |
|     //
 | |
|     InitializeDebugIdt ();
 | |
|     //
 | |
|     // Build mailbox in HOB and setup Mailbox Set In Pei flag
 | |
|     //
 | |
|     Mailbox = AllocateZeroPool (sizeof (DEBUG_AGENT_MAILBOX));
 | |
|     MailboxLocation = (UINT64)(UINTN)Mailbox;
 | |
|     MailboxLocationPointer = BuildGuidDataHob (
 | |
|                                &gEfiDebugAgentGuid,
 | |
|                                &MailboxLocation,
 | |
|                                sizeof (UINT64)
 | |
|                                );
 | |
| 
 | |
|     InitializeDebugTimer ();
 | |
|     //
 | |
|     // Update IDT entry to save the location pointer saved mailbox pointer
 | |
|     //
 | |
|     SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer);
 | |
|     //
 | |
|     // Save init arch type when debug agent initialized
 | |
|     //
 | |
|     SetDebugFlag (DEBUG_AGENT_FLAG_INIT_ARCH, DEBUG_ARCH_SYMBOL);
 | |
|     //
 | |
|     // Register for a callback once memory has been initialized.
 | |
|     // If memery has been ready, the callback funtion will be invoked immediately
 | |
|     //
 | |
|     Status = PeiServicesNotifyPpi (&mMemoryDiscoveredNotifyList[0]);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       DEBUG ((EFI_D_ERROR, "DebugAgent: Failed to register memory discovered callback function!\n"));
 | |
|       CpuDeadLoop ();
 | |
|     }
 | |
|     //
 | |
|     // Set HOB check flag if memory has not been ready yet
 | |
|     //
 | |
|     if (GetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY) == 0) {
 | |
|       SetDebugFlag (DEBUG_AGENT_FLAG_CHECK_MAILBOX_IN_HOB, 1);
 | |
|     }
 | |
| 
 | |
|     Phase2Context.InitFlag = InitFlag;
 | |
|     Phase2Context.Context  = Context;
 | |
|     Phase2Context.Function = Function;
 | |
|     DebugPortInitialize ((VOID *) &Phase2Context, InitializeDebugAgentPhase2);
 | |
| 
 | |
|     FindAndReportModuleImageInfo (4);
 | |
| 
 | |
|     break;
 | |
| 
 | |
|   case DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64:
 | |
|     if (Context == NULL) {
 | |
|       DEBUG ((EFI_D_ERROR, "DebugAgent: Input parameter Context cannot be NULL!\n"));
 | |
|       CpuDeadLoop ();
 | |
|     } else {
 | |
|       Ia32Idtr =  (IA32_DESCRIPTOR *) Context;
 | |
|       Ia32IdtEntry = (IA32_IDT_ENTRY *)(Ia32Idtr->Base);
 | |
|       MailboxLocationPointer = (UINT64 *) (UINTN) (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow +
 | |
|                                                 (Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16));
 | |
|       Mailbox = (DEBUG_AGENT_MAILBOX *) (UINTN)(*MailboxLocationPointer);
 | |
|       //
 | |
|       // Mailbox should valid and setup before executing thunk code
 | |
|       //
 | |
|       VerifyMailboxChecksum (Mailbox);
 | |
| 
 | |
|       DebugPortHandle = (UINT64) (UINTN)DebugPortInitialize ((VOID *)(UINTN)Mailbox->DebugPortHandle, NULL);
 | |
|       UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
 | |
|       //
 | |
|       // Set up IDT entries
 | |
|       //
 | |
|       InitializeDebugIdt ();
 | |
|       //
 | |
|       // Update IDT entry to save location pointer saved the mailbox pointer
 | |
|       //
 | |
|       SetLocationSavedMailboxPointerInIdtEntry (MailboxLocationPointer);
 | |
| 
 | |
|       FindAndReportModuleImageInfo (4);
 | |
|     }
 | |
|     break;
 | |
| 
 | |
|   default:
 | |
|     //
 | |
|     // Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this 
 | |
|     // Debug Agent library instance.
 | |
|     //
 | |
|     DEBUG ((EFI_D_ERROR, "Debug Agent: The InitFlag value is not allowed!\n"));
 | |
|     CpuDeadLoop ();
 | |
|     break;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Enable CPU interrupts so debug timer interrupts can be delivered
 | |
|   //
 | |
|   EnableInterrupts ();
 | |
| 
 | |
|   //
 | |
|   // If Function is not NULL, invoke it always whatever debug agent was initialized sucesssfully or not.
 | |
|   //
 | |
|   if (Function != NULL) {
 | |
|     Function (Context);
 | |
|   }
 | |
|   //
 | |
|   // Set return status for DEBUG_AGENT_INIT_PEI
 | |
|   //
 | |
|   if (InitFlag == DEBUG_AGENT_INIT_PEI && Context != NULL) {
 | |
|     *(EFI_STATUS *)Context = EFI_SUCCESS;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Caller provided function to be invoked at the end of DebugPortInitialize().
 | |
| 
 | |
|   Refer to the descrption for DebugPortInitialize() for more details.
 | |
| 
 | |
|   @param[in] Context           The first input argument of DebugPortInitialize().
 | |
|   @param[in] DebugPortHandle   Debug port handle created by Debug Communication Libary.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| InitializeDebugAgentPhase2 (
 | |
|   IN VOID                  *Context,
 | |
|   IN DEBUG_PORT_HANDLE     DebugPortHandle
 | |
|   )
 | |
| {
 | |
|   DEBUG_AGENT_PHASE2_CONTEXT *Phase2Context;
 | |
|   UINT64                     *MailboxLocation;
 | |
|   DEBUG_AGENT_MAILBOX        *Mailbox;
 | |
|   EFI_SEC_PEI_HAND_OFF       *SecCoreData;
 | |
|   UINT16                     BufferSize;
 | |
|   UINT64                     NewDebugPortHandle;
 | |
| 
 | |
|   Phase2Context = (DEBUG_AGENT_PHASE2_CONTEXT *) Context;
 | |
|   MailboxLocation = GetLocationSavedMailboxPointerInIdtEntry ();
 | |
|   Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
 | |
|   BufferSize = PcdGet16(PcdDebugPortHandleBufferSize);
 | |
|   if (Phase2Context->InitFlag == DEBUG_AGENT_INIT_PEI) {
 | |
|     NewDebugPortHandle = (UINT64)(UINTN)AllocateCopyPool (BufferSize, DebugPortHandle);
 | |
|   } else {
 | |
|     NewDebugPortHandle = (UINT64)(UINTN)DebugPortHandle;
 | |
|   }
 | |
|   UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, NewDebugPortHandle);
 | |
| 
 | |
|   //
 | |
|   // Trigger one software interrupt to inform HOST
 | |
|   //
 | |
|   TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE);
 | |
| 
 | |
|   if (Phase2Context->InitFlag == DEBUG_AGENT_INIT_PREMEM_SEC) {
 | |
|     //
 | |
|     // If Temporary RAM region is below 128 MB, then send message to 
 | |
|     // host to disable low memory filtering.
 | |
|     //
 | |
|     SecCoreData = (EFI_SEC_PEI_HAND_OFF *)Phase2Context->Context;
 | |
|     if ((UINTN)SecCoreData->TemporaryRamBase < BASE_128MB && IsHostAttached ()) {
 | |
|       SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
 | |
|       TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
 | |
|     }
 | |
|     //
 | |
|     // Enable CPU interrupts so debug timer interrupts can be delivered
 | |
|     //
 | |
|     EnableInterrupts ();
 | |
|     //
 | |
|     // Call continuation function if it is not NULL.
 | |
|     //
 | |
|     Phase2Context->Function (Phase2Context->Context);
 | |
|   }
 | |
| }
 |