summaryrefslogtreecommitdiff
path: root/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent
diff options
context:
space:
mode:
Diffstat (limited to 'SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent')
-rw-r--r--SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.c1098
-rw-r--r--SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.h68
-rw-r--r--SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/SerialIo.c1654
3 files changed, 1410 insertions, 1410 deletions
diff --git a/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.c b/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.c
index a41bba2c4b..7bea778378 100644
--- a/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.c
+++ b/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.c
@@ -1,549 +1,549 @@
-/** @file
- Debug Agent library implementation for Dxe Core and Dxr modules.
-
- Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeDebugAgentLib.h"
-
-DEBUG_AGENT_MAILBOX mMailbox;
-DEBUG_AGENT_MAILBOX *mMailboxPointer = NULL;
-IA32_IDT_GATE_DESCRIPTOR mIdtEntryTable[33];
-BOOLEAN mDxeCoreFlag = FALSE;
-BOOLEAN mMultiProcessorDebugSupport = FALSE;
-VOID *mSavedIdtTable = NULL;
-UINTN mSaveIdtTableSize = 0;
-BOOLEAN mDebugAgentInitialized = FALSE;
-BOOLEAN mSkipBreakpoint = FALSE;
-
-/**
- Check if debug agent support multi-processor.
-
- @retval TRUE Multi-processor is supported.
- @retval FALSE Multi-processor is not supported.
-
-**/
-BOOLEAN
-MultiProcessorDebugSupport (
- VOID
- )
-{
- return mMultiProcessorDebugSupport;
-}
-
-/**
- Internal constructor worker function.
-
- It will register one callback function on EFI PCD Protocol.
- It will allocate the NVS memory to store Mailbox and install configuration table
- in system table to store its pointer.
-
-**/
-VOID
-InternalConstructorWorker (
- VOID
- )
-{
- EFI_STATUS Status;
- EFI_PHYSICAL_ADDRESS Address;
- BOOLEAN DebugTimerInterruptState;
- DEBUG_AGENT_MAILBOX *Mailbox;
- DEBUG_AGENT_MAILBOX *NewMailbox;
- EFI_HOB_GUID_TYPE *GuidHob;
- EFI_VECTOR_HANDOFF_INFO *VectorHandoffInfo;
-
- //
- // Check persisted vector handoff info
- //
- Status = EFI_SUCCESS;
- GuidHob = GetFirstGuidHob (&gEfiVectorHandoffInfoPpiGuid);
- if ((GuidHob != NULL) && !mDxeCoreFlag) {
- //
- // Check if configuration table is installed or not if GUIDed HOB existed,
- // only when Debug Agent is not linked by DXE Core
- //
- Status = EfiGetSystemConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID **)&VectorHandoffInfo);
- }
-
- if ((GuidHob == NULL) || (Status != EFI_SUCCESS)) {
- //
- // Install configuration table for persisted vector handoff info if GUIDed HOB cannot be found or
- // configuration table does not exist
- //
- Status = gBS->InstallConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID *)&mVectorHandoffInfoDebugAgent[0]);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "DebugAgent: Cannot install configuration table for persisted vector handoff info!\n"));
- CpuDeadLoop ();
- }
- }
-
- //
- // Install EFI Serial IO protocol on debug port
- //
- InstallSerialIo ();
-
- Address = 0;
- Status = gBS->AllocatePages (
- AllocateAnyPages,
- EfiACPIMemoryNVS,
- EFI_SIZE_TO_PAGES (sizeof (DEBUG_AGENT_MAILBOX) + PcdGet16 (PcdDebugPortHandleBufferSize)),
- &Address
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "DebugAgent: Cannot install configuration table for mailbox!\n"));
- CpuDeadLoop ();
- }
-
- DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (FALSE);
-
- 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 may be free at runtime, SMM debug agent needs to access them
- //
- Mailbox = GetMailboxPointer ();
- CopyMem (NewMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
- CopyMem (NewMailbox + 1, (VOID *)(UINTN)Mailbox->DebugPortHandle, PcdGet16 (PcdDebugPortHandleBufferSize));
- //
- // Update Debug Port Handle in new Mailbox
- //
- UpdateMailboxContent (NewMailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, (UINT64)(UINTN)(NewMailbox + 1));
- mMailboxPointer = NewMailbox;
-
- DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState);
-
- Status = gBS->InstallConfigurationTable (&gEfiDebugAgentGuid, (VOID *)mMailboxPointer);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "DebugAgent: Failed to install configuration for mailbox!\n"));
- CpuDeadLoop ();
- }
-}
-
-/**
- Debug Agent constructor function.
-
- @param[in] ImageHandle The firmware allocated handle for the EFI image.
- @param[in] SystemTable A pointer to the EFI System Table.
-
- @retval RETURN_SUCCESS When this function completed.
-
-**/
-RETURN_STATUS
-EFIAPI
-DxeDebugAgentLibConstructor (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- if (mDxeCoreFlag) {
- //
- // Invoke internal constructor function only when DXE core links this library instance
- //
- InternalConstructorWorker ();
- }
-
- return RETURN_SUCCESS;
-}
-
-/**
- Get the pointer to Mailbox from the configuration table.
-
- @return Pointer to Mailbox.
-
-**/
-DEBUG_AGENT_MAILBOX *
-GetMailboxFromConfigurationTable (
- VOID
- )
-{
- EFI_STATUS Status;
- DEBUG_AGENT_MAILBOX *Mailbox;
-
- Status = EfiGetSystemConfigurationTable (&gEfiDebugAgentGuid, (VOID **)&Mailbox);
- if ((Status == EFI_SUCCESS) && (Mailbox != NULL)) {
- VerifyMailboxChecksum (Mailbox);
- return Mailbox;
- } else {
- return NULL;
- }
-}
-
-/**
- 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;
- UINT64 *MailboxLocation;
- DEBUG_AGENT_MAILBOX *Mailbox;
-
- GuidHob = GetNextGuidHob (&gEfiDebugAgentGuid, HobStart);
- if (GuidHob == NULL) {
- return NULL;
- }
-
- MailboxLocation = (UINT64 *)(GET_GUID_HOB_DATA (GuidHob));
- Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
- VerifyMailboxChecksum (Mailbox);
-
- return Mailbox;
-}
-
-/**
- Get Debug Agent Mailbox pointer.
-
- @return Mailbox pointer.
-
-**/
-DEBUG_AGENT_MAILBOX *
-GetMailboxPointer (
- VOID
- )
-{
- AcquireMpSpinLock (&mDebugMpContext.MailboxSpinLock);
- VerifyMailboxChecksum (mMailboxPointer);
- ReleaseMpSpinLock (&mDebugMpContext.MailboxSpinLock);
- return mMailboxPointer;
-}
-
-/**
- Get debug port handle.
-
- @return Debug port handle.
-
-**/
-DEBUG_PORT_HANDLE
-GetDebugPortHandle (
- VOID
- )
-{
- return (DEBUG_PORT_HANDLE)(UINTN)(GetMailboxPointer ()->DebugPortHandle);
-}
-
-/**
- Worker function to set up Debug Agent environment.
-
- This function will set up IDT table and initialize the IDT entries and
- initialize CPU LOCAL APIC timer.
- It also tries to connect HOST if Debug Agent was not initialized before.
-
- @param[in] Mailbox Pointer to Mailbox.
-
-**/
-VOID
-SetupDebugAgentEnvironment (
- IN DEBUG_AGENT_MAILBOX *Mailbox
- )
-{
- IA32_DESCRIPTOR Idtr;
- UINT16 IdtEntryCount;
- UINT64 DebugPortHandle;
- UINT32 DebugTimerFrequency;
-
- if (mMultiProcessorDebugSupport) {
- InitializeSpinLock (&mDebugMpContext.MpContextSpinLock);
- InitializeSpinLock (&mDebugMpContext.DebugPortSpinLock);
- InitializeSpinLock (&mDebugMpContext.MailboxSpinLock);
- //
- // Clear Break CPU index value
- //
- mDebugMpContext.BreakAtCpuIndex = (UINT32)-1;
- }
-
- //
- // Get original IDT address and size.
- //
- AsmReadIdtr ((IA32_DESCRIPTOR *)&Idtr);
- IdtEntryCount = (UINT16)((Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR));
- if (IdtEntryCount < 33) {
- ZeroMem (&mIdtEntryTable, sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33);
- //
- // Copy original IDT table into new one
- //
- CopyMem (&mIdtEntryTable, (VOID *)Idtr.Base, Idtr.Limit + 1);
- //
- // Load new IDT table
- //
- 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 ();
-
- //
- // If mMailboxPointer is not set before, set it
- //
- if (mMailboxPointer == NULL) {
- if (Mailbox != NULL) {
- //
- // If Mailbox exists, copy it into one global variable
- //
- CopyMem (&mMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
- } else {
- ZeroMem (&mMailbox, sizeof (DEBUG_AGENT_MAILBOX));
- }
-
- mMailboxPointer = &mMailbox;
- }
-
- //
- // Initialize Debug Timer hardware and save its initial count and frequency
- //
- mDebugMpContext.DebugTimerInitCount = InitializeDebugTimer (&DebugTimerFrequency, TRUE);
- UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency);
- //
- // Initialize debug communication port
- //
- DebugPortHandle = (UINT64)(UINTN)DebugPortInitialize ((VOID *)(UINTN)mMailboxPointer->DebugPortHandle, NULL);
- UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
-
- if (Mailbox == NULL) {
- //
- // Trigger one software interrupt to inform HOST
- //
- TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE);
- SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
- //
- // Memory has been ready
- //
- if (IsHostAttached ()) {
- //
- // Trigger one software interrupt to inform HOST
- //
- TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
- }
- }
-}
-
-/**
- Initialize debug agent.
-
- This function is used to set up debug environment 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
- )
-{
- UINT64 *MailboxLocation;
- DEBUG_AGENT_MAILBOX *Mailbox;
- BOOLEAN InterruptStatus;
- VOID *HobList;
- IA32_DESCRIPTOR IdtDescriptor;
- IA32_DESCRIPTOR *Ia32Idtr;
- IA32_IDT_ENTRY *Ia32IdtEntry;
- BOOLEAN PeriodicMode;
- UINTN TimerCycle;
-
- if (InitFlag == DEBUG_AGENT_INIT_DXE_AP) {
- //
- // Check if CPU APIC Timer is working, otherwise initialize it.
- //
- InitializeLocalApicSoftwareEnable (TRUE);
- GetApicTimerState (NULL, &PeriodicMode, NULL);
- TimerCycle = GetApicTimerInitCount ();
- if (!PeriodicMode || (TimerCycle == 0)) {
- InitializeDebugTimer (NULL, FALSE);
- }
-
- //
- // Invoked by AP, enable interrupt to let AP could receive IPI from other processors
- //
- EnableInterrupts ();
- return;
- }
-
- //
- // Disable Debug Timer interrupt
- //
- SaveAndSetDebugTimerInterrupt (FALSE);
- //
- // Save and disable original interrupt status
- //
- InterruptStatus = SaveAndDisableInterrupts ();
-
- //
- // Try to get mailbox firstly
- //
- HobList = NULL;
- Mailbox = NULL;
- MailboxLocation = NULL;
-
- switch (InitFlag) {
- case DEBUG_AGENT_INIT_DXE_LOAD:
- //
- // Check if Debug Agent has been initialized before
- //
- if (IsDebugAgentInitialzed ()) {
- DEBUG ((DEBUG_INFO, "Debug Agent: The former agent will be overwritten by the new one!\n"));
- }
-
- mMultiProcessorDebugSupport = TRUE;
- //
- // Save original IDT table
- //
- AsmReadIdtr (&IdtDescriptor);
- mSaveIdtTableSize = IdtDescriptor.Limit + 1;
- mSavedIdtTable = AllocateCopyPool (mSaveIdtTableSize, (VOID *)IdtDescriptor.Base);
- //
- // Check if Debug Agent initialized in DXE phase
- //
- Mailbox = GetMailboxFromConfigurationTable ();
- if (Mailbox == NULL) {
- //
- // Try to get mailbox from GUIDed HOB build in PEI
- //
- HobList = GetHobList ();
- Mailbox = GetMailboxFromHob (HobList);
- }
-
- //
- // Set up Debug Agent Environment and try to connect HOST if required
- //
- SetupDebugAgentEnvironment (Mailbox);
- //
- // For DEBUG_AGENT_INIT_S3, needn't to install configuration table and EFI Serial IO protocol
- // For DEBUG_AGENT_INIT_DXE_CORE, InternalConstructorWorker() will invoked in Constructor()
- //
- InternalConstructorWorker ();
- //
- // Enable Debug Timer interrupt
- //
- SaveAndSetDebugTimerInterrupt (TRUE);
- //
- // Enable interrupt to receive Debug Timer interrupt
- //
- EnableInterrupts ();
-
- mDebugAgentInitialized = TRUE;
- FindAndReportModuleImageInfo (SIZE_4KB);
-
- *(EFI_STATUS *)Context = EFI_SUCCESS;
-
- break;
-
- case DEBUG_AGENT_INIT_DXE_UNLOAD:
- if (mDebugAgentInitialized) {
- if (IsHostAttached ()) {
- *(EFI_STATUS *)Context = EFI_ACCESS_DENIED;
- //
- // Enable Debug Timer interrupt again
- //
- SaveAndSetDebugTimerInterrupt (TRUE);
- } else {
- //
- // Restore original IDT table
- //
- AsmReadIdtr (&IdtDescriptor);
- IdtDescriptor.Limit = (UINT16)(mSaveIdtTableSize - 1);
- CopyMem ((VOID *)IdtDescriptor.Base, mSavedIdtTable, mSaveIdtTableSize);
- AsmWriteIdtr (&IdtDescriptor);
- FreePool (mSavedIdtTable);
- mDebugAgentInitialized = FALSE;
- *(EFI_STATUS *)Context = EFI_SUCCESS;
- }
- } else {
- *(EFI_STATUS *)Context = EFI_NOT_STARTED;
- }
-
- //
- // Restore interrupt state.
- //
- SetInterruptState (InterruptStatus);
- break;
-
- case DEBUG_AGENT_INIT_DXE_CORE:
- mDxeCoreFlag = TRUE;
- mMultiProcessorDebugSupport = TRUE;
- //
- // Try to get mailbox from GUIDed HOB build in PEI
- //
- HobList = Context;
- Mailbox = GetMailboxFromHob (HobList);
- //
- // Set up Debug Agent Environment and try to connect HOST if required
- //
- SetupDebugAgentEnvironment (Mailbox);
- //
- // Enable Debug Timer interrupt
- //
- SaveAndSetDebugTimerInterrupt (TRUE);
- //
- // Enable interrupt to receive Debug Timer interrupt
- //
- EnableInterrupts ();
-
- break;
-
- case DEBUG_AGENT_INIT_S3:
-
- if (Context != NULL) {
- Ia32Idtr = (IA32_DESCRIPTOR *)Context;
- Ia32IdtEntry = (IA32_IDT_ENTRY *)(Ia32Idtr->Base);
- MailboxLocation = (UINT64 *)((UINTN)Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow +
- ((UINTN)Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16));
- Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
- VerifyMailboxChecksum (Mailbox);
- }
-
- //
- // Save Mailbox pointer in global variable
- //
- mMailboxPointer = Mailbox;
- //
- // Set up Debug Agent Environment and try to connect HOST if required
- //
- SetupDebugAgentEnvironment (Mailbox);
- //
- // Disable interrupt
- //
- DisableInterrupts ();
- FindAndReportModuleImageInfo (SIZE_4KB);
- if (GetDebugFlag (DEBUG_AGENT_FLAG_BREAK_BOOT_SCRIPT) == 1) {
- //
- // If Boot Script entry break is set, code will be break at here.
- //
- CpuBreakpoint ();
- }
-
- 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;
- }
-}
+/** @file
+ Debug Agent library implementation for Dxe Core and Dxr modules.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeDebugAgentLib.h"
+
+DEBUG_AGENT_MAILBOX mMailbox;
+DEBUG_AGENT_MAILBOX *mMailboxPointer = NULL;
+IA32_IDT_GATE_DESCRIPTOR mIdtEntryTable[33];
+BOOLEAN mDxeCoreFlag = FALSE;
+BOOLEAN mMultiProcessorDebugSupport = FALSE;
+VOID *mSavedIdtTable = NULL;
+UINTN mSaveIdtTableSize = 0;
+BOOLEAN mDebugAgentInitialized = FALSE;
+BOOLEAN mSkipBreakpoint = FALSE;
+
+/**
+ Check if debug agent support multi-processor.
+
+ @retval TRUE Multi-processor is supported.
+ @retval FALSE Multi-processor is not supported.
+
+**/
+BOOLEAN
+MultiProcessorDebugSupport (
+ VOID
+ )
+{
+ return mMultiProcessorDebugSupport;
+}
+
+/**
+ Internal constructor worker function.
+
+ It will register one callback function on EFI PCD Protocol.
+ It will allocate the NVS memory to store Mailbox and install configuration table
+ in system table to store its pointer.
+
+**/
+VOID
+InternalConstructorWorker (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Address;
+ BOOLEAN DebugTimerInterruptState;
+ DEBUG_AGENT_MAILBOX *Mailbox;
+ DEBUG_AGENT_MAILBOX *NewMailbox;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ EFI_VECTOR_HANDOFF_INFO *VectorHandoffInfo;
+
+ //
+ // Check persisted vector handoff info
+ //
+ Status = EFI_SUCCESS;
+ GuidHob = GetFirstGuidHob (&gEfiVectorHandoffInfoPpiGuid);
+ if ((GuidHob != NULL) && !mDxeCoreFlag) {
+ //
+ // Check if configuration table is installed or not if GUIDed HOB existed,
+ // only when Debug Agent is not linked by DXE Core
+ //
+ Status = EfiGetSystemConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID **)&VectorHandoffInfo);
+ }
+
+ if ((GuidHob == NULL) || (Status != EFI_SUCCESS)) {
+ //
+ // Install configuration table for persisted vector handoff info if GUIDed HOB cannot be found or
+ // configuration table does not exist
+ //
+ Status = gBS->InstallConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID *)&mVectorHandoffInfoDebugAgent[0]);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "DebugAgent: Cannot install configuration table for persisted vector handoff info!\n"));
+ CpuDeadLoop ();
+ }
+ }
+
+ //
+ // Install EFI Serial IO protocol on debug port
+ //
+ InstallSerialIo ();
+
+ Address = 0;
+ Status = gBS->AllocatePages (
+ AllocateAnyPages,
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES (sizeof (DEBUG_AGENT_MAILBOX) + PcdGet16 (PcdDebugPortHandleBufferSize)),
+ &Address
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "DebugAgent: Cannot install configuration table for mailbox!\n"));
+ CpuDeadLoop ();
+ }
+
+ DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (FALSE);
+
+ 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 may be free at runtime, SMM debug agent needs to access them
+ //
+ Mailbox = GetMailboxPointer ();
+ CopyMem (NewMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
+ CopyMem (NewMailbox + 1, (VOID *)(UINTN)Mailbox->DebugPortHandle, PcdGet16 (PcdDebugPortHandleBufferSize));
+ //
+ // Update Debug Port Handle in new Mailbox
+ //
+ UpdateMailboxContent (NewMailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, (UINT64)(UINTN)(NewMailbox + 1));
+ mMailboxPointer = NewMailbox;
+
+ DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState);
+
+ Status = gBS->InstallConfigurationTable (&gEfiDebugAgentGuid, (VOID *)mMailboxPointer);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "DebugAgent: Failed to install configuration for mailbox!\n"));
+ CpuDeadLoop ();
+ }
+}
+
+/**
+ Debug Agent constructor function.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval RETURN_SUCCESS When this function completed.
+
+**/
+RETURN_STATUS
+EFIAPI
+DxeDebugAgentLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ if (mDxeCoreFlag) {
+ //
+ // Invoke internal constructor function only when DXE core links this library instance
+ //
+ InternalConstructorWorker ();
+ }
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Get the pointer to Mailbox from the configuration table.
+
+ @return Pointer to Mailbox.
+
+**/
+DEBUG_AGENT_MAILBOX *
+GetMailboxFromConfigurationTable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ DEBUG_AGENT_MAILBOX *Mailbox;
+
+ Status = EfiGetSystemConfigurationTable (&gEfiDebugAgentGuid, (VOID **)&Mailbox);
+ if ((Status == EFI_SUCCESS) && (Mailbox != NULL)) {
+ VerifyMailboxChecksum (Mailbox);
+ return Mailbox;
+ } else {
+ return NULL;
+ }
+}
+
+/**
+ 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;
+ UINT64 *MailboxLocation;
+ DEBUG_AGENT_MAILBOX *Mailbox;
+
+ GuidHob = GetNextGuidHob (&gEfiDebugAgentGuid, HobStart);
+ if (GuidHob == NULL) {
+ return NULL;
+ }
+
+ MailboxLocation = (UINT64 *)(GET_GUID_HOB_DATA (GuidHob));
+ Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
+ VerifyMailboxChecksum (Mailbox);
+
+ return Mailbox;
+}
+
+/**
+ Get Debug Agent Mailbox pointer.
+
+ @return Mailbox pointer.
+
+**/
+DEBUG_AGENT_MAILBOX *
+GetMailboxPointer (
+ VOID
+ )
+{
+ AcquireMpSpinLock (&mDebugMpContext.MailboxSpinLock);
+ VerifyMailboxChecksum (mMailboxPointer);
+ ReleaseMpSpinLock (&mDebugMpContext.MailboxSpinLock);
+ return mMailboxPointer;
+}
+
+/**
+ Get debug port handle.
+
+ @return Debug port handle.
+
+**/
+DEBUG_PORT_HANDLE
+GetDebugPortHandle (
+ VOID
+ )
+{
+ return (DEBUG_PORT_HANDLE)(UINTN)(GetMailboxPointer ()->DebugPortHandle);
+}
+
+/**
+ Worker function to set up Debug Agent environment.
+
+ This function will set up IDT table and initialize the IDT entries and
+ initialize CPU LOCAL APIC timer.
+ It also tries to connect HOST if Debug Agent was not initialized before.
+
+ @param[in] Mailbox Pointer to Mailbox.
+
+**/
+VOID
+SetupDebugAgentEnvironment (
+ IN DEBUG_AGENT_MAILBOX *Mailbox
+ )
+{
+ IA32_DESCRIPTOR Idtr;
+ UINT16 IdtEntryCount;
+ UINT64 DebugPortHandle;
+ UINT32 DebugTimerFrequency;
+
+ if (mMultiProcessorDebugSupport) {
+ InitializeSpinLock (&mDebugMpContext.MpContextSpinLock);
+ InitializeSpinLock (&mDebugMpContext.DebugPortSpinLock);
+ InitializeSpinLock (&mDebugMpContext.MailboxSpinLock);
+ //
+ // Clear Break CPU index value
+ //
+ mDebugMpContext.BreakAtCpuIndex = (UINT32)-1;
+ }
+
+ //
+ // Get original IDT address and size.
+ //
+ AsmReadIdtr ((IA32_DESCRIPTOR *)&Idtr);
+ IdtEntryCount = (UINT16)((Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR));
+ if (IdtEntryCount < 33) {
+ ZeroMem (&mIdtEntryTable, sizeof (IA32_IDT_GATE_DESCRIPTOR) * 33);
+ //
+ // Copy original IDT table into new one
+ //
+ CopyMem (&mIdtEntryTable, (VOID *)Idtr.Base, Idtr.Limit + 1);
+ //
+ // Load new IDT table
+ //
+ 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 ();
+
+ //
+ // If mMailboxPointer is not set before, set it
+ //
+ if (mMailboxPointer == NULL) {
+ if (Mailbox != NULL) {
+ //
+ // If Mailbox exists, copy it into one global variable
+ //
+ CopyMem (&mMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX));
+ } else {
+ ZeroMem (&mMailbox, sizeof (DEBUG_AGENT_MAILBOX));
+ }
+
+ mMailboxPointer = &mMailbox;
+ }
+
+ //
+ // Initialize Debug Timer hardware and save its initial count and frequency
+ //
+ mDebugMpContext.DebugTimerInitCount = InitializeDebugTimer (&DebugTimerFrequency, TRUE);
+ UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_TIMER_FREQUENCY, DebugTimerFrequency);
+ //
+ // Initialize debug communication port
+ //
+ DebugPortHandle = (UINT64)(UINTN)DebugPortInitialize ((VOID *)(UINTN)mMailboxPointer->DebugPortHandle, NULL);
+ UpdateMailboxContent (mMailboxPointer, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, DebugPortHandle);
+
+ if (Mailbox == NULL) {
+ //
+ // Trigger one software interrupt to inform HOST
+ //
+ TriggerSoftInterrupt (SYSTEM_RESET_SIGNATURE);
+ SetDebugFlag (DEBUG_AGENT_FLAG_MEMORY_READY, 1);
+ //
+ // Memory has been ready
+ //
+ if (IsHostAttached ()) {
+ //
+ // Trigger one software interrupt to inform HOST
+ //
+ TriggerSoftInterrupt (MEMORY_READY_SIGNATURE);
+ }
+ }
+}
+
+/**
+ Initialize debug agent.
+
+ This function is used to set up debug environment 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
+ )
+{
+ UINT64 *MailboxLocation;
+ DEBUG_AGENT_MAILBOX *Mailbox;
+ BOOLEAN InterruptStatus;
+ VOID *HobList;
+ IA32_DESCRIPTOR IdtDescriptor;
+ IA32_DESCRIPTOR *Ia32Idtr;
+ IA32_IDT_ENTRY *Ia32IdtEntry;
+ BOOLEAN PeriodicMode;
+ UINTN TimerCycle;
+
+ if (InitFlag == DEBUG_AGENT_INIT_DXE_AP) {
+ //
+ // Check if CPU APIC Timer is working, otherwise initialize it.
+ //
+ InitializeLocalApicSoftwareEnable (TRUE);
+ GetApicTimerState (NULL, &PeriodicMode, NULL);
+ TimerCycle = GetApicTimerInitCount ();
+ if (!PeriodicMode || (TimerCycle == 0)) {
+ InitializeDebugTimer (NULL, FALSE);
+ }
+
+ //
+ // Invoked by AP, enable interrupt to let AP could receive IPI from other processors
+ //
+ EnableInterrupts ();
+ return;
+ }
+
+ //
+ // Disable Debug Timer interrupt
+ //
+ SaveAndSetDebugTimerInterrupt (FALSE);
+ //
+ // Save and disable original interrupt status
+ //
+ InterruptStatus = SaveAndDisableInterrupts ();
+
+ //
+ // Try to get mailbox firstly
+ //
+ HobList = NULL;
+ Mailbox = NULL;
+ MailboxLocation = NULL;
+
+ switch (InitFlag) {
+ case DEBUG_AGENT_INIT_DXE_LOAD:
+ //
+ // Check if Debug Agent has been initialized before
+ //
+ if (IsDebugAgentInitialzed ()) {
+ DEBUG ((DEBUG_INFO, "Debug Agent: The former agent will be overwritten by the new one!\n"));
+ }
+
+ mMultiProcessorDebugSupport = TRUE;
+ //
+ // Save original IDT table
+ //
+ AsmReadIdtr (&IdtDescriptor);
+ mSaveIdtTableSize = IdtDescriptor.Limit + 1;
+ mSavedIdtTable = AllocateCopyPool (mSaveIdtTableSize, (VOID *)IdtDescriptor.Base);
+ //
+ // Check if Debug Agent initialized in DXE phase
+ //
+ Mailbox = GetMailboxFromConfigurationTable ();
+ if (Mailbox == NULL) {
+ //
+ // Try to get mailbox from GUIDed HOB build in PEI
+ //
+ HobList = GetHobList ();
+ Mailbox = GetMailboxFromHob (HobList);
+ }
+
+ //
+ // Set up Debug Agent Environment and try to connect HOST if required
+ //
+ SetupDebugAgentEnvironment (Mailbox);
+ //
+ // For DEBUG_AGENT_INIT_S3, needn't to install configuration table and EFI Serial IO protocol
+ // For DEBUG_AGENT_INIT_DXE_CORE, InternalConstructorWorker() will invoked in Constructor()
+ //
+ InternalConstructorWorker ();
+ //
+ // Enable Debug Timer interrupt
+ //
+ SaveAndSetDebugTimerInterrupt (TRUE);
+ //
+ // Enable interrupt to receive Debug Timer interrupt
+ //
+ EnableInterrupts ();
+
+ mDebugAgentInitialized = TRUE;
+ FindAndReportModuleImageInfo (SIZE_4KB);
+
+ *(EFI_STATUS *)Context = EFI_SUCCESS;
+
+ break;
+
+ case DEBUG_AGENT_INIT_DXE_UNLOAD:
+ if (mDebugAgentInitialized) {
+ if (IsHostAttached ()) {
+ *(EFI_STATUS *)Context = EFI_ACCESS_DENIED;
+ //
+ // Enable Debug Timer interrupt again
+ //
+ SaveAndSetDebugTimerInterrupt (TRUE);
+ } else {
+ //
+ // Restore original IDT table
+ //
+ AsmReadIdtr (&IdtDescriptor);
+ IdtDescriptor.Limit = (UINT16)(mSaveIdtTableSize - 1);
+ CopyMem ((VOID *)IdtDescriptor.Base, mSavedIdtTable, mSaveIdtTableSize);
+ AsmWriteIdtr (&IdtDescriptor);
+ FreePool (mSavedIdtTable);
+ mDebugAgentInitialized = FALSE;
+ *(EFI_STATUS *)Context = EFI_SUCCESS;
+ }
+ } else {
+ *(EFI_STATUS *)Context = EFI_NOT_STARTED;
+ }
+
+ //
+ // Restore interrupt state.
+ //
+ SetInterruptState (InterruptStatus);
+ break;
+
+ case DEBUG_AGENT_INIT_DXE_CORE:
+ mDxeCoreFlag = TRUE;
+ mMultiProcessorDebugSupport = TRUE;
+ //
+ // Try to get mailbox from GUIDed HOB build in PEI
+ //
+ HobList = Context;
+ Mailbox = GetMailboxFromHob (HobList);
+ //
+ // Set up Debug Agent Environment and try to connect HOST if required
+ //
+ SetupDebugAgentEnvironment (Mailbox);
+ //
+ // Enable Debug Timer interrupt
+ //
+ SaveAndSetDebugTimerInterrupt (TRUE);
+ //
+ // Enable interrupt to receive Debug Timer interrupt
+ //
+ EnableInterrupts ();
+
+ break;
+
+ case DEBUG_AGENT_INIT_S3:
+
+ if (Context != NULL) {
+ Ia32Idtr = (IA32_DESCRIPTOR *)Context;
+ Ia32IdtEntry = (IA32_IDT_ENTRY *)(Ia32Idtr->Base);
+ MailboxLocation = (UINT64 *)((UINTN)Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow +
+ ((UINTN)Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16));
+ Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);
+ VerifyMailboxChecksum (Mailbox);
+ }
+
+ //
+ // Save Mailbox pointer in global variable
+ //
+ mMailboxPointer = Mailbox;
+ //
+ // Set up Debug Agent Environment and try to connect HOST if required
+ //
+ SetupDebugAgentEnvironment (Mailbox);
+ //
+ // Disable interrupt
+ //
+ DisableInterrupts ();
+ FindAndReportModuleImageInfo (SIZE_4KB);
+ if (GetDebugFlag (DEBUG_AGENT_FLAG_BREAK_BOOT_SCRIPT) == 1) {
+ //
+ // If Boot Script entry break is set, code will be break at here.
+ //
+ CpuBreakpoint ();
+ }
+
+ 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;
+ }
+}
diff --git a/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.h b/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.h
index bd178db3e1..8d1d917a6a 100644
--- a/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.h
+++ b/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/DxeDebugAgentLib.h
@@ -1,34 +1,34 @@
-/** @file
- Header file for Dxe Core Debug Agent Library instance.
-
- Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _DXE_CORE_DEBUG_AGENT_LIB_H_
-#define _DXE_CORE_DEBUG_AGENT_LIB_H_
-
-#include <PiDxe.h>
-
-#include <Protocol/SerialIo.h>
-#include <Protocol/DevicePath.h>
-#include <Protocol/PiPcd.h>
-
-#include <Library/UefiBootServicesTableLib.h>
-#include <Library/UefiLib.h>
-#include <Library/DevicePathLib.h>
-#include <Library/MemoryAllocationLib.h>
-
-#include "DebugAgent.h"
-
-/**
- Install EFI Serial IO protocol based on Debug Communication Library.
-
-**/
-VOID
-InstallSerialIo (
- VOID
- );
-
-#endif
+/** @file
+ Header file for Dxe Core Debug Agent Library instance.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _DXE_CORE_DEBUG_AGENT_LIB_H_
+#define _DXE_CORE_DEBUG_AGENT_LIB_H_
+
+#include <PiDxe.h>
+
+#include <Protocol/SerialIo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/PiPcd.h>
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include "DebugAgent.h"
+
+/**
+ Install EFI Serial IO protocol based on Debug Communication Library.
+
+**/
+VOID
+InstallSerialIo (
+ VOID
+ );
+
+#endif
diff --git a/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/SerialIo.c b/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/SerialIo.c
index 97d30c802d..51ae757d2b 100644
--- a/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/SerialIo.c
+++ b/SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgent/SerialIo.c
@@ -1,827 +1,827 @@
-/** @file
- Install Serial IO Protocol that layers on top of a Debug Communication Library instance.
-
- Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeDebugAgentLib.h"
-
-//
-// Serial I/O Protocol Interface definitions.
-//
-
-/**
- Reset serial device.
-
- @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
-
- @retval EFI_SUCCESS Reset successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-SerialReset (
- IN EFI_SERIAL_IO_PROTOCOL *This
- );
-
-/**
- Set new attributes to a serial device.
-
- @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
- @param[in] BaudRate The baudrate of the serial device.
- @param[in] ReceiveFifoDepth The depth of receive FIFO buffer.
- @param[in] Timeout The request timeout for a single char.
- @param[in] Parity The type of parity used in serial device.
- @param[in] DataBits Number of databits used in serial device.
- @param[in] StopBits Number of stopbits used in serial device.
-
- @retval EFI_SUCCESS The new attributes were set.
- @retval EFI_INVALID_PARAMETER One or more attributes have an unsupported value.
- @retval EFI_DEVICE_ERROR The serial device is not functioning correctly (no return).
-
-**/
-EFI_STATUS
-EFIAPI
-SerialSetAttributes (
- IN EFI_SERIAL_IO_PROTOCOL *This,
- IN UINT64 BaudRate,
- IN UINT32 ReceiveFifoDepth,
- IN UINT32 Timeout,
- IN EFI_PARITY_TYPE Parity,
- IN UINT8 DataBits,
- IN EFI_STOP_BITS_TYPE StopBits
- );
-
-/**
- Set Control Bits.
-
- @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
- @param[in] Control Control bits that can be settable.
-
- @retval EFI_SUCCESS New Control bits were set successfully.
- @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported.
-
-**/
-EFI_STATUS
-EFIAPI
-SerialSetControl (
- IN EFI_SERIAL_IO_PROTOCOL *This,
- IN UINT32 Control
- );
-
-/**
- Get ControlBits.
-
- @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
- @param[out] Control Control signals of the serial device.
-
- @retval EFI_SUCCESS Get Control signals successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-SerialGetControl (
- IN EFI_SERIAL_IO_PROTOCOL *This,
- OUT UINT32 *Control
- );
-
-/**
- Write the specified number of bytes to serial device.
-
- @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
- @param[in, out] BufferSize On input the size of Buffer, on output the amount of
- data actually written.
- @param[in] Buffer The buffer of data to write.
-
- @retval EFI_SUCCESS The data were written successfully.
- @retval EFI_DEVICE_ERROR The device reported an error.
- @retval EFI_TIMEOUT The write operation was stopped due to timeout.
-
-**/
-EFI_STATUS
-EFIAPI
-SerialWrite (
- IN EFI_SERIAL_IO_PROTOCOL *This,
- IN OUT UINTN *BufferSize,
- IN VOID *Buffer
- );
-
-/**
- Read the specified number of bytes from serial device.
-
- @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
- @param[in, out] BufferSize On input the size of Buffer, on output the amount of
- data returned in buffer.
- @param[out] Buffer The buffer to return the data into.
-
- @retval EFI_SUCCESS The data were read successfully.
- @retval EFI_DEVICE_ERROR The device reported an error.
- @retval EFI_TIMEOUT The read operation was stopped due to timeout.
-
-**/
-EFI_STATUS
-EFIAPI
-SerialRead (
- IN EFI_SERIAL_IO_PROTOCOL *This,
- IN OUT UINTN *BufferSize,
- OUT VOID *Buffer
- );
-
-//
-// Serial Driver Defaults
-//
-#define SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH 1
-#define SERIAL_PORT_DEFAULT_TIMEOUT 1000000
-#define SERIAL_PORT_DEFAULT_CONTROL_MASK 0
-#define SERIAL_PORT_LOOPBACK_BUFFER_FULL BIT8
-
-//
-// EFI_SERIAL_IO_MODE instance
-//
-EFI_SERIAL_IO_MODE mSerialIoMode = {
- SERIAL_PORT_DEFAULT_CONTROL_MASK,
- SERIAL_PORT_DEFAULT_TIMEOUT,
- 0, // default BaudRate
- SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH,
- 0, // default DataBits
- 0, // default Parity
- 0 // default StopBits
-};
-
-//
-// EFI_SERIAL_IO_PROTOCOL instance
-//
-EFI_SERIAL_IO_PROTOCOL mSerialIo = {
- SERIAL_IO_INTERFACE_REVISION,
- SerialReset,
- SerialSetAttributes,
- SerialSetControl,
- SerialGetControl,
- SerialWrite,
- SerialRead,
- &mSerialIoMode
-};
-
-//
-// Serial IO Device Path definition
-//
-typedef struct {
- VENDOR_DEVICE_PATH VendorDevicePath;
- UART_DEVICE_PATH UartDevicePath;
- EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
-} SERIAL_IO_DEVICE_PATH;
-
-//
-// Serial IO Device Patch instance
-//
-SERIAL_IO_DEVICE_PATH mSerialIoDevicePath = {
- {
- {
- HARDWARE_DEVICE_PATH,
- HW_VENDOR_DP,
- {
- (UINT8)(sizeof (VENDOR_DEVICE_PATH)),
- (UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8)
- }
- },
- EFI_DEBUG_AGENT_GUID,
- },
- {
- {
- MESSAGING_DEVICE_PATH,
- MSG_UART_DP,
- {
- (UINT8)(sizeof (UART_DEVICE_PATH)),
- (UINT8)((sizeof (UART_DEVICE_PATH)) >> 8)
- }
- },
- 0,
- 0, // default BaudRate
- 0, // default DataBits
- 0, // default Parity
- 0, // default StopBits
- },
- {
- END_DEVICE_PATH_TYPE,
- END_ENTIRE_DEVICE_PATH_SUBTYPE,
- {
- END_DEVICE_PATH_LENGTH,
- 0
- }
- }
-};
-
-#define DEBUG_SERIAL_IO_FIFO_DEPTH 10
-//
-// Data buffer for Terminal input character and Debug Symbols.
-// The depth is DEBUG_SERIAL_IO_FIFO_DEPTH.
-// Fields:
-// First UINT8: The index of the first data in array Data[].
-// Last UINT8: The index, which you can put a new data into array Data[].
-// Surplus UINT8: Identify how many data you can put into array Data[].
-// Data[] UINT8: An array, which used to store data.
-//
-typedef struct {
- UINT8 First;
- UINT8 Last;
- UINT8 Surplus;
- UINT8 Data[DEBUG_SERIAL_IO_FIFO_DEPTH];
-} DEBUG_SERIAL_FIFO;
-
-//
-// Global Variables
-//
-EFI_HANDLE mSerialIoHandle = NULL;
-UINTN mLoopbackBuffer = 0;
-DEBUG_SERIAL_FIFO mSerialFifoForTerminal = {
- 0, 0, DEBUG_SERIAL_IO_FIFO_DEPTH, { 0 }
-};
-DEBUG_SERIAL_FIFO mSerialFifoForDebug = {
- 0, 0, DEBUG_SERIAL_IO_FIFO_DEPTH, { 0 }
-};
-
-/**
- Detect whether specific FIFO is empty or not.
-
- @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
-
- @return whether specific FIFO is empty or not.
-
-**/
-BOOLEAN
-IsDebugTerminalFifoEmpty (
- IN DEBUG_SERIAL_FIFO *Fifo
- )
-{
- if (Fifo->Surplus == DEBUG_SERIAL_IO_FIFO_DEPTH) {
- return TRUE;
- }
-
- return FALSE;
-}
-
-/**
- Detect whether specific FIFO is full or not.
-
- @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
-
- @return whether specific FIFO is full or not.
-
-**/
-BOOLEAN
-IsDebugTerminalFifoFull (
- IN DEBUG_SERIAL_FIFO *Fifo
- )
-
-{
- if (Fifo->Surplus == 0) {
- return TRUE;
- }
-
- return FALSE;
-}
-
-/**
- Add data to specific FIFO.
-
- @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
- @param[in] Data The data added to FIFO.
-
- @retval EFI_SUCCESS Add data to specific FIFO successfully.
- @retval EFI_OUT_OF_RESOURCE Failed to add data because FIFO is already full.
-
-**/
-EFI_STATUS
-DebugTerminalFifoAdd (
- IN DEBUG_SERIAL_FIFO *Fifo,
- IN UINT8 Data
- )
-
-{
- //
- // if FIFO full can not add data
- //
- if (IsDebugTerminalFifoFull (Fifo)) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- //
- // FIFO is not full can add data
- //
- Fifo->Data[Fifo->Last] = Data;
- Fifo->Surplus--;
- Fifo->Last++;
- if (Fifo->Last == DEBUG_SERIAL_IO_FIFO_DEPTH) {
- Fifo->Last = 0;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Remove data from specific FIFO.
-
- @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
- @param[out] Data The data removed from FIFO.
-
- @retval EFI_SUCCESS Remove data from specific FIFO successfully.
- @retval EFI_OUT_OF_RESOURCE Failed to remove data because FIFO is empty.
-
-**/
-EFI_STATUS
-DebugTerminalFifoRemove (
- IN DEBUG_SERIAL_FIFO *Fifo,
- OUT UINT8 *Data
- )
-{
- //
- // if FIFO is empty, no data can remove
- //
- if (IsDebugTerminalFifoEmpty (Fifo)) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- //
- // FIFO is not empty, can remove data
- //
- *Data = Fifo->Data[Fifo->First];
- Fifo->Surplus++;
- Fifo->First++;
- if (Fifo->First == DEBUG_SERIAL_IO_FIFO_DEPTH) {
- Fifo->First = 0;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Install EFI Serial IO protocol based on Debug Communication Library.
-
-**/
-VOID
-InstallSerialIo (
- VOID
- )
-{
- EFI_STATUS Status;
-
- Status = gBS->InstallMultipleProtocolInterfaces (
- &mSerialIoHandle,
- &gEfiDevicePathProtocolGuid,
- &mSerialIoDevicePath,
- &gEfiSerialIoProtocolGuid,
- &mSerialIo,
- NULL
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "Debug Agent: Failed to install EFI Serial IO Protocol on Debug Port!\n"));
- }
-}
-
-/**
- Reset serial device.
-
- @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
-
- @retval EFI_SUCCESS Reset successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-SerialReset (
- IN EFI_SERIAL_IO_PROTOCOL *This
- )
-{
- mSerialIoMode.ControlMask = SERIAL_PORT_DEFAULT_CONTROL_MASK;
- mLoopbackBuffer = 0;
- //
- // Not reset serial device hardware indeed.
- //
- return EFI_SUCCESS;
-}
-
-/**
- Set new attributes to a serial device.
-
- @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
- @param[in] BaudRate The baudrate of the serial device.
- @param[in] ReceiveFifoDepth The depth of receive FIFO buffer.
- @param[in] Timeout The request timeout for a single char.
- @param[in] Parity The type of parity used in serial device.
- @param[in] DataBits Number of databits used in serial device.
- @param[in] StopBits Number of stopbits used in serial device.
-
- @retval EFI_SUCCESS The new attributes were set.
- @retval EFI_INVALID_PARAMETER One or more attributes have an unsupported value.
- @retval EFI_DEVICE_ERROR The serial device is not functioning correctly (no return).
-
-**/
-EFI_STATUS
-EFIAPI
-SerialSetAttributes (
- IN EFI_SERIAL_IO_PROTOCOL *This,
- IN UINT64 BaudRate,
- IN UINT32 ReceiveFifoDepth,
- IN UINT32 Timeout,
- IN EFI_PARITY_TYPE Parity,
- IN UINT8 DataBits,
- IN EFI_STOP_BITS_TYPE StopBits
- )
-{
- //
- // The Debug Communication Library CAN NOT change communications parameters (if it has)
- // actually. Because it also has no any idea on what parameters are based on, we cannot
- // check the input parameters (like BaudRate, Parity, DataBits and StopBits).
- //
-
- //
- // Update the Timeout value in the mode structure based on the request.
- // The Debug Communication Library can not support a timeout on writes, but the timeout on
- // reads can be provided by this module.
- //
- if (Timeout == 0) {
- mSerialIoMode.Timeout = SERIAL_PORT_DEFAULT_TIMEOUT;
- } else {
- mSerialIoMode.Timeout = Timeout;
- }
-
- //
- // Update the ReceiveFifoDepth value in the mode structure based on the request.
- // This module assumes that the Debug Communication Library uses a FIFO depth of
- // SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH. The Debug Communication Library may actually be
- // using a larger FIFO, but there is no way to tell.
- //
- if ((ReceiveFifoDepth == 0) || (ReceiveFifoDepth >= SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH)) {
- mSerialIoMode.ReceiveFifoDepth = SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH;
- } else {
- return EFI_INVALID_PARAMETER;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Set Control Bits.
-
- @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
- @param[in] Control Control bits that can be settable.
-
- @retval EFI_SUCCESS New Control bits were set successfully.
- @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported.
-
-**/
-EFI_STATUS
-EFIAPI
-SerialSetControl (
- IN EFI_SERIAL_IO_PROTOCOL *This,
- IN UINT32 Control
- )
-{
- //
- // The only control bit supported by this module is software loopback.
- // If any other bit is set, then return an error
- //
- if ((Control & (~EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE)) != 0) {
- return EFI_UNSUPPORTED;
- }
-
- mSerialIoMode.ControlMask = Control;
- return EFI_SUCCESS;
-}
-
-/**
- Get ControlBits.
-
- @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
- @param[out] Control Control signals of the serial device.
-
- @retval EFI_SUCCESS Get Control signals successfully.
-
-**/
-EFI_STATUS
-EFIAPI
-SerialGetControl (
- IN EFI_SERIAL_IO_PROTOCOL *This,
- OUT UINT32 *Control
- )
-{
- DEBUG_PORT_HANDLE Handle;
- BOOLEAN DebugTimerInterruptState;
- EFI_TPL Tpl;
-
- //
- // Raise TPL to prevent recursion from EFI timer interrupts
- //
- Tpl = gBS->RaiseTPL (TPL_NOTIFY);
-
- //
- // Save and disable Debug Timer interrupt to avoid it to access Debug Port
- //
- DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (FALSE);
- Handle = GetDebugPortHandle ();
-
- //
- // Always assume the output buffer is empty and the Debug Communication Library can process
- // more write requests.
- //
- *Control = mSerialIoMode.ControlMask | EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
-
- //
- // Check to see if the Terminal FIFO is empty and
- // check to see if the input buffer in the Debug Communication Library is empty
- //
- if (!IsDebugTerminalFifoEmpty (&mSerialFifoForTerminal) || DebugPortPollBuffer (Handle)) {
- *Control &= ~EFI_SERIAL_INPUT_BUFFER_EMPTY;
- }
-
- //
- // Restore Debug Timer interrupt
- //
- SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState);
-
- //
- // Restore to original TPL
- //
- gBS->RestoreTPL (Tpl);
-
- return EFI_SUCCESS;
-}
-
-/**
- Write the specified number of bytes to serial device.
-
- @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
- @param[in, out] BufferSize On input the size of Buffer, on output the amount of
- data actually written.
- @param[in] Buffer The buffer of data to write.
-
- @retval EFI_SUCCESS The data were written successfully.
- @retval EFI_DEVICE_ERROR The device reported an error.
- @retval EFI_TIMEOUT The write operation was stopped due to timeout.
-
-**/
-EFI_STATUS
-EFIAPI
-SerialWrite (
- IN EFI_SERIAL_IO_PROTOCOL *This,
- IN OUT UINTN *BufferSize,
- IN VOID *Buffer
- )
-{
- DEBUG_PORT_HANDLE Handle;
- BOOLEAN DebugTimerInterruptState;
- EFI_TPL Tpl;
-
- //
- // Raise TPL to prevent recursion from EFI timer interrupts
- //
- Tpl = gBS->RaiseTPL (TPL_NOTIFY);
-
- //
- // Save and disable Debug Timer interrupt to avoid it to access Debug Port
- //
- DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (FALSE);
- Handle = GetDebugPortHandle ();
-
- if ((mSerialIoMode.ControlMask & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) != 0) {
- if (*BufferSize == 0) {
- return EFI_SUCCESS;
- }
-
- if ((mLoopbackBuffer & SERIAL_PORT_LOOPBACK_BUFFER_FULL) != 0) {
- *BufferSize = 0;
- return EFI_TIMEOUT;
- }
-
- mLoopbackBuffer = SERIAL_PORT_LOOPBACK_BUFFER_FULL | *(UINT8 *)Buffer;
- *BufferSize = 1;
- } else {
- *BufferSize = DebugPortWriteBuffer (Handle, Buffer, *BufferSize);
- }
-
- //
- // Restore Debug Timer interrupt
- //
- SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState);
-
- //
- // Restore to original TPL
- //
- gBS->RestoreTPL (Tpl);
-
- return EFI_SUCCESS;
-}
-
-/**
- Read the specified number of bytes from serial device.
-
- @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
- @param[in, out] BufferSize On input the size of Buffer, on output the amount of
- data returned in buffer.
- @param[out] Buffer The buffer to return the data into.
-
- @retval EFI_SUCCESS The data were read successfully.
- @retval EFI_DEVICE_ERROR The device reported an error.
- @retval EFI_TIMEOUT The read operation was stopped due to timeout.
-
-**/
-EFI_STATUS
-EFIAPI
-SerialRead (
- IN EFI_SERIAL_IO_PROTOCOL *This,
- IN OUT UINTN *BufferSize,
- OUT VOID *Buffer
- )
-{
- EFI_STATUS Status;
- UINTN Index;
- UINT8 *Uint8Buffer;
- BOOLEAN DebugTimerInterruptState;
- EFI_TPL Tpl;
- DEBUG_PORT_HANDLE Handle;
- DEBUG_PACKET_HEADER DebugHeader;
- UINT8 *Data8;
-
- //
- // Raise TPL to prevent recursion from EFI timer interrupts
- //
- Tpl = gBS->RaiseTPL (TPL_NOTIFY);
-
- //
- // Save and disable Debug Timer interrupt to avoid it to access Debug Port
- //
- DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (FALSE);
- Handle = GetDebugPortHandle ();
-
- Data8 = (UINT8 *)&DebugHeader;
- Uint8Buffer = (UINT8 *)Buffer;
- if ((mSerialIoMode.ControlMask & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) != 0) {
- if ((mLoopbackBuffer & SERIAL_PORT_LOOPBACK_BUFFER_FULL) == 0) {
- return EFI_TIMEOUT;
- }
-
- *Uint8Buffer = (UINT8)(mLoopbackBuffer & 0xff);
- mLoopbackBuffer = 0;
- *BufferSize = 1;
- } else {
- for (Index = 0; Index < *BufferSize; Index++) {
- //
- // Read input character from terminal FIFO firstly
- //
- Status = DebugTerminalFifoRemove (&mSerialFifoForTerminal, Data8);
- if (Status == EFI_SUCCESS) {
- *Uint8Buffer = *Data8;
- Uint8Buffer++;
- continue;
- }
-
- //
- // Read the input character from Debug Port
- //
- if (!DebugPortPollBuffer (Handle)) {
- break;
- }
-
- DebugAgentReadBuffer (Handle, Data8, 1, 0);
-
- if (*Data8 == DEBUG_STARTING_SYMBOL_ATTACH) {
- //
- // Add the debug symbol into Debug FIFO
- //
- DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Terminal Timer attach symbol received %x", *Data8);
- DebugTerminalFifoAdd (&mSerialFifoForDebug, *Data8);
- } else if (*Data8 == DEBUG_STARTING_SYMBOL_NORMAL) {
- Status = ReadRemainingBreakPacket (Handle, &DebugHeader);
- if (Status == EFI_SUCCESS) {
- DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Terminal Timer break symbol received %x", DebugHeader.Command);
- DebugTerminalFifoAdd (&mSerialFifoForDebug, DebugHeader.Command);
- }
-
- if (Status == EFI_TIMEOUT) {
- continue;
- }
- } else {
- *Uint8Buffer = *Data8;
- Uint8Buffer++;
- }
- }
-
- *BufferSize = (UINTN)Uint8Buffer - (UINTN)Buffer;
- }
-
- //
- // Restore Debug Timer interrupt
- //
- SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState);
-
- //
- // Restore to original TPL
- //
- gBS->RestoreTPL (Tpl);
-
- return EFI_SUCCESS;
-}
-
-/**
- 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
-DebugReadBreakFromDebugPort (
- 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) {
- DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Debug Timer attach symbol received %x", *Data8);
- *BreakSymbol = *Data8;
- return EFI_SUCCESS;
- }
-
- if (*Data8 == DEBUG_STARTING_SYMBOL_NORMAL) {
- Status = ReadRemainingBreakPacket (Handle, &DebugHeader);
- if (Status == EFI_SUCCESS) {
- DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Debug Timer break symbol received %x", DebugHeader.Command);
- *BreakSymbol = DebugHeader.Command;
- return EFI_SUCCESS;
- }
-
- if (Status == EFI_TIMEOUT) {
- break;
- }
- } else {
- //
- // Add to Terminal FIFO
- //
- DebugTerminalFifoAdd (&mSerialFifoForTerminal, *Data8);
- }
- }
-
- return EFI_NOT_FOUND;
-}
-
-/**
- Read the Attach/Break-in symbols.
-
- @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;
- UINT8 Data8;
-
- //
- // Read break symbol from debug FIFO firstly
- //
- Status = DebugTerminalFifoRemove (&mSerialFifoForDebug, &Data8);
- if (Status == EFI_SUCCESS) {
- *BreakSymbol = Data8;
- return EFI_SUCCESS;
- } else {
- //
- // Read Break symbol from debug port
- //
- return DebugReadBreakFromDebugPort (Handle, BreakSymbol);
- }
-}
+/** @file
+ Install Serial IO Protocol that layers on top of a Debug Communication Library instance.
+
+ Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DxeDebugAgentLib.h"
+
+//
+// Serial I/O Protocol Interface definitions.
+//
+
+/**
+ Reset serial device.
+
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
+
+ @retval EFI_SUCCESS Reset successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialReset (
+ IN EFI_SERIAL_IO_PROTOCOL *This
+ );
+
+/**
+ Set new attributes to a serial device.
+
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
+ @param[in] BaudRate The baudrate of the serial device.
+ @param[in] ReceiveFifoDepth The depth of receive FIFO buffer.
+ @param[in] Timeout The request timeout for a single char.
+ @param[in] Parity The type of parity used in serial device.
+ @param[in] DataBits Number of databits used in serial device.
+ @param[in] StopBits Number of stopbits used in serial device.
+
+ @retval EFI_SUCCESS The new attributes were set.
+ @retval EFI_INVALID_PARAMETER One or more attributes have an unsupported value.
+ @retval EFI_DEVICE_ERROR The serial device is not functioning correctly (no return).
+
+**/
+EFI_STATUS
+EFIAPI
+SerialSetAttributes (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ IN UINT64 BaudRate,
+ IN UINT32 ReceiveFifoDepth,
+ IN UINT32 Timeout,
+ IN EFI_PARITY_TYPE Parity,
+ IN UINT8 DataBits,
+ IN EFI_STOP_BITS_TYPE StopBits
+ );
+
+/**
+ Set Control Bits.
+
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
+ @param[in] Control Control bits that can be settable.
+
+ @retval EFI_SUCCESS New Control bits were set successfully.
+ @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialSetControl (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ IN UINT32 Control
+ );
+
+/**
+ Get ControlBits.
+
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
+ @param[out] Control Control signals of the serial device.
+
+ @retval EFI_SUCCESS Get Control signals successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialGetControl (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ OUT UINT32 *Control
+ );
+
+/**
+ Write the specified number of bytes to serial device.
+
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
+ @param[in, out] BufferSize On input the size of Buffer, on output the amount of
+ data actually written.
+ @param[in] Buffer The buffer of data to write.
+
+ @retval EFI_SUCCESS The data were written successfully.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_TIMEOUT The write operation was stopped due to timeout.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialWrite (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+ Read the specified number of bytes from serial device.
+
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
+ @param[in, out] BufferSize On input the size of Buffer, on output the amount of
+ data returned in buffer.
+ @param[out] Buffer The buffer to return the data into.
+
+ @retval EFI_SUCCESS The data were read successfully.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_TIMEOUT The read operation was stopped due to timeout.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialRead (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ );
+
+//
+// Serial Driver Defaults
+//
+#define SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH 1
+#define SERIAL_PORT_DEFAULT_TIMEOUT 1000000
+#define SERIAL_PORT_DEFAULT_CONTROL_MASK 0
+#define SERIAL_PORT_LOOPBACK_BUFFER_FULL BIT8
+
+//
+// EFI_SERIAL_IO_MODE instance
+//
+EFI_SERIAL_IO_MODE mSerialIoMode = {
+ SERIAL_PORT_DEFAULT_CONTROL_MASK,
+ SERIAL_PORT_DEFAULT_TIMEOUT,
+ 0, // default BaudRate
+ SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH,
+ 0, // default DataBits
+ 0, // default Parity
+ 0 // default StopBits
+};
+
+//
+// EFI_SERIAL_IO_PROTOCOL instance
+//
+EFI_SERIAL_IO_PROTOCOL mSerialIo = {
+ SERIAL_IO_INTERFACE_REVISION,
+ SerialReset,
+ SerialSetAttributes,
+ SerialSetControl,
+ SerialGetControl,
+ SerialWrite,
+ SerialRead,
+ &mSerialIoMode
+};
+
+//
+// Serial IO Device Path definition
+//
+typedef struct {
+ VENDOR_DEVICE_PATH VendorDevicePath;
+ UART_DEVICE_PATH UartDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
+} SERIAL_IO_DEVICE_PATH;
+
+//
+// Serial IO Device Patch instance
+//
+SERIAL_IO_DEVICE_PATH mSerialIoDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8)(sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ EFI_DEBUG_AGENT_GUID,
+ },
+ {
+ {
+ MESSAGING_DEVICE_PATH,
+ MSG_UART_DP,
+ {
+ (UINT8)(sizeof (UART_DEVICE_PATH)),
+ (UINT8)((sizeof (UART_DEVICE_PATH)) >> 8)
+ }
+ },
+ 0,
+ 0, // default BaudRate
+ 0, // default DataBits
+ 0, // default Parity
+ 0, // default StopBits
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ END_DEVICE_PATH_LENGTH,
+ 0
+ }
+ }
+};
+
+#define DEBUG_SERIAL_IO_FIFO_DEPTH 10
+//
+// Data buffer for Terminal input character and Debug Symbols.
+// The depth is DEBUG_SERIAL_IO_FIFO_DEPTH.
+// Fields:
+// First UINT8: The index of the first data in array Data[].
+// Last UINT8: The index, which you can put a new data into array Data[].
+// Surplus UINT8: Identify how many data you can put into array Data[].
+// Data[] UINT8: An array, which used to store data.
+//
+typedef struct {
+ UINT8 First;
+ UINT8 Last;
+ UINT8 Surplus;
+ UINT8 Data[DEBUG_SERIAL_IO_FIFO_DEPTH];
+} DEBUG_SERIAL_FIFO;
+
+//
+// Global Variables
+//
+EFI_HANDLE mSerialIoHandle = NULL;
+UINTN mLoopbackBuffer = 0;
+DEBUG_SERIAL_FIFO mSerialFifoForTerminal = {
+ 0, 0, DEBUG_SERIAL_IO_FIFO_DEPTH, { 0 }
+};
+DEBUG_SERIAL_FIFO mSerialFifoForDebug = {
+ 0, 0, DEBUG_SERIAL_IO_FIFO_DEPTH, { 0 }
+};
+
+/**
+ Detect whether specific FIFO is empty or not.
+
+ @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
+
+ @return whether specific FIFO is empty or not.
+
+**/
+BOOLEAN
+IsDebugTerminalFifoEmpty (
+ IN DEBUG_SERIAL_FIFO *Fifo
+ )
+{
+ if (Fifo->Surplus == DEBUG_SERIAL_IO_FIFO_DEPTH) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Detect whether specific FIFO is full or not.
+
+ @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
+
+ @return whether specific FIFO is full or not.
+
+**/
+BOOLEAN
+IsDebugTerminalFifoFull (
+ IN DEBUG_SERIAL_FIFO *Fifo
+ )
+
+{
+ if (Fifo->Surplus == 0) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Add data to specific FIFO.
+
+ @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
+ @param[in] Data The data added to FIFO.
+
+ @retval EFI_SUCCESS Add data to specific FIFO successfully.
+ @retval EFI_OUT_OF_RESOURCE Failed to add data because FIFO is already full.
+
+**/
+EFI_STATUS
+DebugTerminalFifoAdd (
+ IN DEBUG_SERIAL_FIFO *Fifo,
+ IN UINT8 Data
+ )
+
+{
+ //
+ // if FIFO full can not add data
+ //
+ if (IsDebugTerminalFifoFull (Fifo)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // FIFO is not full can add data
+ //
+ Fifo->Data[Fifo->Last] = Data;
+ Fifo->Surplus--;
+ Fifo->Last++;
+ if (Fifo->Last == DEBUG_SERIAL_IO_FIFO_DEPTH) {
+ Fifo->Last = 0;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Remove data from specific FIFO.
+
+ @param[in] Fifo A pointer to the Data Structure DEBUG_SERIAL_FIFO.
+ @param[out] Data The data removed from FIFO.
+
+ @retval EFI_SUCCESS Remove data from specific FIFO successfully.
+ @retval EFI_OUT_OF_RESOURCE Failed to remove data because FIFO is empty.
+
+**/
+EFI_STATUS
+DebugTerminalFifoRemove (
+ IN DEBUG_SERIAL_FIFO *Fifo,
+ OUT UINT8 *Data
+ )
+{
+ //
+ // if FIFO is empty, no data can remove
+ //
+ if (IsDebugTerminalFifoEmpty (Fifo)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // FIFO is not empty, can remove data
+ //
+ *Data = Fifo->Data[Fifo->First];
+ Fifo->Surplus++;
+ Fifo->First++;
+ if (Fifo->First == DEBUG_SERIAL_IO_FIFO_DEPTH) {
+ Fifo->First = 0;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Install EFI Serial IO protocol based on Debug Communication Library.
+
+**/
+VOID
+InstallSerialIo (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mSerialIoHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mSerialIoDevicePath,
+ &gEfiSerialIoProtocolGuid,
+ &mSerialIo,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Debug Agent: Failed to install EFI Serial IO Protocol on Debug Port!\n"));
+ }
+}
+
+/**
+ Reset serial device.
+
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
+
+ @retval EFI_SUCCESS Reset successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialReset (
+ IN EFI_SERIAL_IO_PROTOCOL *This
+ )
+{
+ mSerialIoMode.ControlMask = SERIAL_PORT_DEFAULT_CONTROL_MASK;
+ mLoopbackBuffer = 0;
+ //
+ // Not reset serial device hardware indeed.
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Set new attributes to a serial device.
+
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
+ @param[in] BaudRate The baudrate of the serial device.
+ @param[in] ReceiveFifoDepth The depth of receive FIFO buffer.
+ @param[in] Timeout The request timeout for a single char.
+ @param[in] Parity The type of parity used in serial device.
+ @param[in] DataBits Number of databits used in serial device.
+ @param[in] StopBits Number of stopbits used in serial device.
+
+ @retval EFI_SUCCESS The new attributes were set.
+ @retval EFI_INVALID_PARAMETER One or more attributes have an unsupported value.
+ @retval EFI_DEVICE_ERROR The serial device is not functioning correctly (no return).
+
+**/
+EFI_STATUS
+EFIAPI
+SerialSetAttributes (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ IN UINT64 BaudRate,
+ IN UINT32 ReceiveFifoDepth,
+ IN UINT32 Timeout,
+ IN EFI_PARITY_TYPE Parity,
+ IN UINT8 DataBits,
+ IN EFI_STOP_BITS_TYPE StopBits
+ )
+{
+ //
+ // The Debug Communication Library CAN NOT change communications parameters (if it has)
+ // actually. Because it also has no any idea on what parameters are based on, we cannot
+ // check the input parameters (like BaudRate, Parity, DataBits and StopBits).
+ //
+
+ //
+ // Update the Timeout value in the mode structure based on the request.
+ // The Debug Communication Library can not support a timeout on writes, but the timeout on
+ // reads can be provided by this module.
+ //
+ if (Timeout == 0) {
+ mSerialIoMode.Timeout = SERIAL_PORT_DEFAULT_TIMEOUT;
+ } else {
+ mSerialIoMode.Timeout = Timeout;
+ }
+
+ //
+ // Update the ReceiveFifoDepth value in the mode structure based on the request.
+ // This module assumes that the Debug Communication Library uses a FIFO depth of
+ // SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH. The Debug Communication Library may actually be
+ // using a larger FIFO, but there is no way to tell.
+ //
+ if ((ReceiveFifoDepth == 0) || (ReceiveFifoDepth >= SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH)) {
+ mSerialIoMode.ReceiveFifoDepth = SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set Control Bits.
+
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
+ @param[in] Control Control bits that can be settable.
+
+ @retval EFI_SUCCESS New Control bits were set successfully.
+ @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialSetControl (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ IN UINT32 Control
+ )
+{
+ //
+ // The only control bit supported by this module is software loopback.
+ // If any other bit is set, then return an error
+ //
+ if ((Control & (~EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE)) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ mSerialIoMode.ControlMask = Control;
+ return EFI_SUCCESS;
+}
+
+/**
+ Get ControlBits.
+
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
+ @param[out] Control Control signals of the serial device.
+
+ @retval EFI_SUCCESS Get Control signals successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialGetControl (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ OUT UINT32 *Control
+ )
+{
+ DEBUG_PORT_HANDLE Handle;
+ BOOLEAN DebugTimerInterruptState;
+ EFI_TPL Tpl;
+
+ //
+ // Raise TPL to prevent recursion from EFI timer interrupts
+ //
+ Tpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ //
+ // Save and disable Debug Timer interrupt to avoid it to access Debug Port
+ //
+ DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (FALSE);
+ Handle = GetDebugPortHandle ();
+
+ //
+ // Always assume the output buffer is empty and the Debug Communication Library can process
+ // more write requests.
+ //
+ *Control = mSerialIoMode.ControlMask | EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
+
+ //
+ // Check to see if the Terminal FIFO is empty and
+ // check to see if the input buffer in the Debug Communication Library is empty
+ //
+ if (!IsDebugTerminalFifoEmpty (&mSerialFifoForTerminal) || DebugPortPollBuffer (Handle)) {
+ *Control &= ~EFI_SERIAL_INPUT_BUFFER_EMPTY;
+ }
+
+ //
+ // Restore Debug Timer interrupt
+ //
+ SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState);
+
+ //
+ // Restore to original TPL
+ //
+ gBS->RestoreTPL (Tpl);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Write the specified number of bytes to serial device.
+
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
+ @param[in, out] BufferSize On input the size of Buffer, on output the amount of
+ data actually written.
+ @param[in] Buffer The buffer of data to write.
+
+ @retval EFI_SUCCESS The data were written successfully.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_TIMEOUT The write operation was stopped due to timeout.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialWrite (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ )
+{
+ DEBUG_PORT_HANDLE Handle;
+ BOOLEAN DebugTimerInterruptState;
+ EFI_TPL Tpl;
+
+ //
+ // Raise TPL to prevent recursion from EFI timer interrupts
+ //
+ Tpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ //
+ // Save and disable Debug Timer interrupt to avoid it to access Debug Port
+ //
+ DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (FALSE);
+ Handle = GetDebugPortHandle ();
+
+ if ((mSerialIoMode.ControlMask & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) != 0) {
+ if (*BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ if ((mLoopbackBuffer & SERIAL_PORT_LOOPBACK_BUFFER_FULL) != 0) {
+ *BufferSize = 0;
+ return EFI_TIMEOUT;
+ }
+
+ mLoopbackBuffer = SERIAL_PORT_LOOPBACK_BUFFER_FULL | *(UINT8 *)Buffer;
+ *BufferSize = 1;
+ } else {
+ *BufferSize = DebugPortWriteBuffer (Handle, Buffer, *BufferSize);
+ }
+
+ //
+ // Restore Debug Timer interrupt
+ //
+ SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState);
+
+ //
+ // Restore to original TPL
+ //
+ gBS->RestoreTPL (Tpl);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read the specified number of bytes from serial device.
+
+ @param[in] This Pointer to EFI_SERIAL_IO_PROTOCOL.
+ @param[in, out] BufferSize On input the size of Buffer, on output the amount of
+ data returned in buffer.
+ @param[out] Buffer The buffer to return the data into.
+
+ @retval EFI_SUCCESS The data were read successfully.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_TIMEOUT The read operation was stopped due to timeout.
+
+**/
+EFI_STATUS
+EFIAPI
+SerialRead (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINT8 *Uint8Buffer;
+ BOOLEAN DebugTimerInterruptState;
+ EFI_TPL Tpl;
+ DEBUG_PORT_HANDLE Handle;
+ DEBUG_PACKET_HEADER DebugHeader;
+ UINT8 *Data8;
+
+ //
+ // Raise TPL to prevent recursion from EFI timer interrupts
+ //
+ Tpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ //
+ // Save and disable Debug Timer interrupt to avoid it to access Debug Port
+ //
+ DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (FALSE);
+ Handle = GetDebugPortHandle ();
+
+ Data8 = (UINT8 *)&DebugHeader;
+ Uint8Buffer = (UINT8 *)Buffer;
+ if ((mSerialIoMode.ControlMask & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) != 0) {
+ if ((mLoopbackBuffer & SERIAL_PORT_LOOPBACK_BUFFER_FULL) == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ *Uint8Buffer = (UINT8)(mLoopbackBuffer & 0xff);
+ mLoopbackBuffer = 0;
+ *BufferSize = 1;
+ } else {
+ for (Index = 0; Index < *BufferSize; Index++) {
+ //
+ // Read input character from terminal FIFO firstly
+ //
+ Status = DebugTerminalFifoRemove (&mSerialFifoForTerminal, Data8);
+ if (Status == EFI_SUCCESS) {
+ *Uint8Buffer = *Data8;
+ Uint8Buffer++;
+ continue;
+ }
+
+ //
+ // Read the input character from Debug Port
+ //
+ if (!DebugPortPollBuffer (Handle)) {
+ break;
+ }
+
+ DebugAgentReadBuffer (Handle, Data8, 1, 0);
+
+ if (*Data8 == DEBUG_STARTING_SYMBOL_ATTACH) {
+ //
+ // Add the debug symbol into Debug FIFO
+ //
+ DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Terminal Timer attach symbol received %x", *Data8);
+ DebugTerminalFifoAdd (&mSerialFifoForDebug, *Data8);
+ } else if (*Data8 == DEBUG_STARTING_SYMBOL_NORMAL) {
+ Status = ReadRemainingBreakPacket (Handle, &DebugHeader);
+ if (Status == EFI_SUCCESS) {
+ DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Terminal Timer break symbol received %x", DebugHeader.Command);
+ DebugTerminalFifoAdd (&mSerialFifoForDebug, DebugHeader.Command);
+ }
+
+ if (Status == EFI_TIMEOUT) {
+ continue;
+ }
+ } else {
+ *Uint8Buffer = *Data8;
+ Uint8Buffer++;
+ }
+ }
+
+ *BufferSize = (UINTN)Uint8Buffer - (UINTN)Buffer;
+ }
+
+ //
+ // Restore Debug Timer interrupt
+ //
+ SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState);
+
+ //
+ // Restore to original TPL
+ //
+ gBS->RestoreTPL (Tpl);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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
+DebugReadBreakFromDebugPort (
+ 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) {
+ DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Debug Timer attach symbol received %x", *Data8);
+ *BreakSymbol = *Data8;
+ return EFI_SUCCESS;
+ }
+
+ if (*Data8 == DEBUG_STARTING_SYMBOL_NORMAL) {
+ Status = ReadRemainingBreakPacket (Handle, &DebugHeader);
+ if (Status == EFI_SUCCESS) {
+ DebugAgentMsgPrint (DEBUG_AGENT_INFO, "Debug Timer break symbol received %x", DebugHeader.Command);
+ *BreakSymbol = DebugHeader.Command;
+ return EFI_SUCCESS;
+ }
+
+ if (Status == EFI_TIMEOUT) {
+ break;
+ }
+ } else {
+ //
+ // Add to Terminal FIFO
+ //
+ DebugTerminalFifoAdd (&mSerialFifoForTerminal, *Data8);
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Read the Attach/Break-in symbols.
+
+ @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;
+ UINT8 Data8;
+
+ //
+ // Read break symbol from debug FIFO firstly
+ //
+ Status = DebugTerminalFifoRemove (&mSerialFifoForDebug, &Data8);
+ if (Status == EFI_SUCCESS) {
+ *BreakSymbol = Data8;
+ return EFI_SUCCESS;
+ } else {
+ //
+ // Read Break symbol from debug port
+ //
+ return DebugReadBreakFromDebugPort (Handle, BreakSymbol);
+ }
+}