| /** @file | |
| Debug Agent library implementition for Dxe Core and Dxr modules. | |
| Copyright (c) 2010, 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 "DxeDebugAgentLib.h" | |
| DEBUG_AGENT_MAILBOX mMailbox; | |
| DEBUG_AGENT_MAILBOX *mMailboxPointer; | |
| IA32_IDT_GATE_DESCRIPTOR mIdtEntryTable[33]; | |
| BOOLEAN mConfigurationTableNeeded = FALSE; | |
| CONST BOOLEAN MultiProcessorDebugSupport = TRUE; | |
| /** | |
| Constructor allocates the NVS memory to store Mailbox and install configuration table | |
| in system table to store its pointer. | |
| @param[in] ImageHandle The firmware allocated handle for the EFI image. | |
| @param[in] SystemTable A pointer to the EFI System Table. | |
| @retval RETURN_SUCCESS Allocate the global memory space to store guid and function tables. | |
| @retval RETURN_OUT_OF_RESOURCES No enough memory to allocated. | |
| **/ | |
| RETURN_STATUS | |
| EFIAPI | |
| DxeDebugAgentLibConstructor ( | |
| IN EFI_HANDLE ImageHandle, | |
| IN EFI_SYSTEM_TABLE *SystemTable | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_PHYSICAL_ADDRESS Address; | |
| if (!mConfigurationTableNeeded) { | |
| return RETURN_SUCCESS; | |
| } | |
| Address = 0; | |
| Status = gBS->AllocatePages ( | |
| AllocateAnyPages, | |
| EfiACPIMemoryNVS, | |
| EFI_SIZE_TO_PAGES (sizeof (DEBUG_AGENT_MAILBOX)), | |
| &Address | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| CopyMem ( | |
| (UINT8 *) (UINTN) Address, | |
| (UINT8 *) (UINTN) mMailboxPointer, | |
| sizeof (DEBUG_AGENT_MAILBOX) | |
| ); | |
| mMailboxPointer = (DEBUG_AGENT_MAILBOX *) (UINTN) Address; | |
| return gBS->InstallConfigurationTable (&gEfiDebugAgentGuid, (VOID *) mMailboxPointer); | |
| } | |
| /** | |
| Get the pointer to Mailbox from the GUIDed HOB. | |
| @param[in] HobStart The starting HOB pointer to search from. | |
| @return Pointer to Mailbox. | |
| **/ | |
| DEBUG_AGENT_MAILBOX * | |
| GetMailboxFromHob ( | |
| IN VOID *HobStart | |
| ) | |
| { | |
| EFI_HOB_GUID_TYPE *GuidHob; | |
| GuidHob = GetNextGuidHob (&gEfiDebugAgentGuid, HobStart); | |
| if (GuidHob == NULL) { | |
| return NULL; | |
| } | |
| return (DEBUG_AGENT_MAILBOX *) (GET_GUID_HOB_DATA(GuidHob)); | |
| } | |
| /** | |
| Get Debug Agent Mailbox pointer. | |
| @return Mailbox pointer. | |
| **/ | |
| DEBUG_AGENT_MAILBOX * | |
| GetMailboxPointer ( | |
| VOID | |
| ) | |
| { | |
| return mMailboxPointer; | |
| } | |
| /** | |
| Get debug port handle. | |
| @return Debug port handle. | |
| **/ | |
| DEBUG_PORT_HANDLE | |
| GetDebugPortHandle ( | |
| VOID | |
| ) | |
| { | |
| return (DEBUG_PORT_HANDLE) (UINTN)(mMailboxPointer->DebugPortHandle); | |
| } | |
| /** | |
| Initialize debug agent. | |
| This function is used to set up debug enviroment for DXE phase. | |
| If this function is called by DXE Core, Context must be the pointer | |
| to HOB list which will be used to get GUIDed HOB. It will enable | |
| interrupt to support break-in feature. | |
| If this function is called by DXE module, Context must be NULL. It | |
| will enable interrupt to support break-in feature. | |
| @param[in] InitFlag Init flag is used to decide initialize process. | |
| @param[in] Context Context needed according to InitFlag. | |
| @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; | |
| IA32_DESCRIPTOR Idtr; | |
| UINT16 IdtEntryCount; | |
| BOOLEAN InterruptStatus; | |
| if (InitFlag != DEBUG_AGENT_INIT_DXE_CORE && | |
| InitFlag != DEBUG_AGENT_INIT_S3 && | |
| InitFlag != DEBUG_AGENT_INIT_DXE_AP) { | |
| return; | |
| } | |
| // | |
| // Save and disable original interrupt status | |
| // | |
| InterruptStatus = SaveAndDisableInterrupts (); | |
| if (InitFlag == DEBUG_AGENT_INIT_DXE_CORE) { | |
| // | |
| // Try to get Mailbox from GUIDed HOB. | |
| // | |
| mConfigurationTableNeeded = TRUE; | |
| Mailbox = GetMailboxFromHob (Context); | |
| } else if (InitFlag == DEBUG_AGENT_INIT_DXE_AP) { | |
| EnableInterrupts (); | |
| return; | |
| } else { | |
| // | |
| // If it is in S3 path, needn't to install configuration table. | |
| // | |
| Mailbox = NULL; | |
| } | |
| if (Mailbox != NULL) { | |
| // | |
| // If Mailbox exists, copy it into one global variable. | |
| // | |
| CopyMem (&mMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX)); | |
| mMailbox.DebugPortHandle = 0; | |
| } else { | |
| // | |
| // If Mailbox not exists, used the local Mailbox. | |
| // | |
| ZeroMem (&mMailbox, sizeof (DEBUG_AGENT_MAILBOX)); | |
| } | |
| mMailboxPointer = &mMailbox; | |
| // | |
| // Get original IDT address and size. | |
| // | |
| AsmReadIdtr ((IA32_DESCRIPTOR *) &Idtr); | |
| IdtEntryCount = (UINT16) ((Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR)); | |
| if (IdtEntryCount < 33) { | |
| Idtr.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33 - 1); | |
| Idtr.Base = (UINTN) &mIdtEntryTable; | |
| AsmWriteIdtr ((IA32_DESCRIPTOR *) &Idtr); | |
| } | |
| // | |
| // Initialize the IDT table entries to support source level debug. | |
| // | |
| InitializeDebugIdt (); | |
| // | |
| // Initialize debug communication port | |
| // | |
| mMailboxPointer->DebugPortHandle = (UINT64) (UINTN)DebugPortInitialize (NULL, NULL); | |
| InitializeSpinLock (&mDebugMpContext.MpContextSpinLock); | |
| InitializeSpinLock (&mDebugMpContext.DebugPortSpinLock); | |
| if (InitFlag == DEBUG_AGENT_INIT_DXE_CORE) { | |
| // | |
| // Initialize Debug Timer hardware and enable interrupt. | |
| // | |
| InitializeDebugTimer (); | |
| EnableInterrupts (); | |
| return; | |
| } else { | |
| // | |
| // Disable Debug Timer interrupt in S3 path. | |
| // | |
| SaveAndSetDebugTimerInterrupt (FALSE); | |
| // | |
| // Restore interrupt state. | |
| // | |
| SetInterruptState (InterruptStatus); | |
| } | |
| } | |