mirror of https://github.com/acidanthera/audk.git
696 lines
23 KiB
C
696 lines
23 KiB
C
/** @file
|
|
SEC Core Debug Agent Library instance implementition.
|
|
|
|
Copyright (c) 2010 - 2015, 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"
|
|
|
|
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 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
|
|
//
|
|
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 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;
|
|
UINT32 DebugTimerFrequency;
|
|
|
|
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);
|
|
//
|
|
// 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 ((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));
|
|
if (Mailbox == NULL) {
|
|
DEBUG ((EFI_D_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 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 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 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 && 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 CPU interrupts so debug timer interrupts can be delivered
|
|
//
|
|
EnableInterrupts ();
|
|
//
|
|
// Call continuation function if it is not NULL.
|
|
//
|
|
Phase2Context->Function (Phase2Context->Context);
|
|
}
|
|
}
|