REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3737 Apply uncrustify changes to .c/.h files in the SourceLevelDebugPkg package Cc: Andrew Fish <afish@apple.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Hao A Wu <hao.a.wu@intel.com> Reviewed-by: Ray Ni <ray.ni@intel.com>
		
			
				
	
	
		
			722 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			722 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   SEC Core Debug Agent Library instance implementation.
 | |
| 
 | |
|   Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.<BR>
 | |
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "SecPeiDebugAgentLib.h"
 | |
| 
 | |
| GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN  mSkipBreakpoint = FALSE;
 | |
| 
 | |
| GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_VECTOR_HANDOFF_INFO_PPI  mVectorHandoffInfoPpi = {
 | |
|   &mVectorHandoffInfoDebugAgent[0]
 | |
| };
 | |
| 
 | |
| //
 | |
| // Ppis to be installed
 | |
| //
 | |
| GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_PPI_DESCRIPTOR  mVectorHandoffInfoPpiList[] = {
 | |
|   {
 | |
|     (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
 | |
|     &gEfiVectorHandoffInfoPpiGuid,
 | |
|     &mVectorHandoffInfoPpi
 | |
|   }
 | |
| };
 | |
| 
 | |
| GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_NOTIFY_DESCRIPTOR  mDebugAgentMemoryDiscoveredNotifyList[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
 | |
|     //
 | |
|     DebugAgentReadBuffer (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 entry 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 = (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 override 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 Library 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;
 | |
|   UINT32                           DebugTimerFrequency;
 | |
|   BOOLEAN                          CpuInterruptState;
 | |
| 
 | |
|   //
 | |
|   // Disable interrupts and save current interrupt state
 | |
|   //
 | |
|   CpuInterruptState = SaveAndDisableInterrupts ();
 | |
| 
 | |
|   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);
 | |
|       //
 | |
|       // Initialize Debug Timer hardware and save its frequency
 | |
|       //
 | |
|       InitializeDebugTimer (&DebugTimerFrequency, TRUE);
 | |
|       UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency);
 | |
| 
 | |
|       Phase2Context.InitFlag = InitFlag;
 | |
|       Phase2Context.Context  = Context;
 | |
|       Phase2Context.Function = Function;
 | |
|       DebugPortInitialize ((VOID *)&Phase2Context, InitializeDebugAgentPhase2);
 | |
|       //
 | |
|       // If reaches here, it means Debug Port initialization failed.
 | |
|       //
 | |
|       DEBUG ((DEBUG_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 ((DEBUG_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 ((DEBUG_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 ((DEBUG_ERROR, "DebugAgent: Input parameter Context cannot be NULL!\n"));
 | |
|         CpuDeadLoop ();
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Check if Debug Agent has initialized before
 | |
|       //
 | |
|       if (IsDebugAgentInitialzed ()) {
 | |
|         DEBUG ((DEBUG_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 ((DEBUG_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));
 | |
|       if (Mailbox == NULL) {
 | |
|         DEBUG ((DEBUG_ERROR, "DebugAgent: Failed to allocate memory!\n"));
 | |
|         CpuDeadLoop ();
 | |
|       } else {
 | |
|         MailboxLocation        = (UINT64)(UINTN)Mailbox;
 | |
|         MailboxLocationPointer = BuildGuidDataHob (
 | |
|                                    &gEfiDebugAgentGuid,
 | |
|                                    &MailboxLocation,
 | |
|                                    sizeof (UINT64)
 | |
|                                    );
 | |
|         //
 | |
|         // Initialize Debug Timer hardware and save its frequency
 | |
|         //
 | |
|         InitializeDebugTimer (&DebugTimerFrequency, TRUE);
 | |
|         UpdateMailboxContent (Mailbox, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency);
 | |
|         //
 | |
|         // 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 memory has been ready, the callback function will be invoked immediately
 | |
|       //
 | |
|       Status = PeiServicesNotifyPpi (&mDebugAgentMemoryDiscoveredNotifyList[0]);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         DEBUG ((DEBUG_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 ((DEBUG_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 +
 | |
|                                             ((UINTN)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 ((DEBUG_ERROR, "Debug Agent: The InitFlag value is not allowed!\n"));
 | |
|       CpuDeadLoop ();
 | |
|       break;
 | |
|   }
 | |
| 
 | |
|   if (InitFlag == DEBUG_AGENT_INIT_POSTMEM_SEC) {
 | |
|     //
 | |
|     // Restore CPU Interrupt state and keep debug timer interrupt state as is
 | |
|     // in DEBUG_AGENT_INIT_POSTMEM_SEC case
 | |
|     //
 | |
|     SetInterruptState (CpuInterruptState);
 | |
|   } else {
 | |
|     //
 | |
|     // Enable Debug Timer interrupt
 | |
|     //
 | |
|     SaveAndSetDebugTimerInterrupt (TRUE);
 | |
|     //
 | |
|     // Enable CPU interrupts so debug timer interrupts can be delivered
 | |
|     //
 | |
|     EnableInterrupts ();
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // If Function is not NULL, invoke it always whatever debug agent was initialized successfully 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 description for DebugPortInitialize() for more details.
 | |
| 
 | |
|   @param[in] Context           The first input argument of DebugPortInitialize().
 | |
|   @param[in] DebugPortHandle   Debug port handle created by Debug Communication Library.
 | |
| 
 | |
| **/
 | |
| 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) && (BufferSize != 0)) {
 | |
|     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 Debug Timer interrupt
 | |
|     //
 | |
|     SaveAndSetDebugTimerInterrupt (TRUE);
 | |
|     //
 | |
|     // Enable CPU interrupts so debug timer interrupts can be delivered
 | |
|     //
 | |
|     EnableInterrupts ();
 | |
|     //
 | |
|     // Call continuation function if it is not NULL.
 | |
|     //
 | |
|     Phase2Context->Function (Phase2Context->Context);
 | |
|   }
 | |
| }
 |