diff --git a/ArmVirtPkg/Library/DebugLibFdtPL011Uart/DebugLibFdtPL011UartRam.inf b/ArmVirtPkg/Library/DebugLibFdtPL011Uart/DebugLibFdtPL011UartRam.inf new file mode 100644 index 0000000000..a5f4c2d80a --- /dev/null +++ b/ArmVirtPkg/Library/DebugLibFdtPL011Uart/DebugLibFdtPL011UartRam.inf @@ -0,0 +1,60 @@ +## @file +# DebugLib instance that produces debug output directly via PL011UartLib. +# +# If there are at least two PL011 UARTs in the device tree, and the /chosen +# node's "stdout-path" property references one PL011 UART, then both raw +# SerialPortLib IO, and -- via SerialDxe -- UEFI console IO, will occur on that +# UART; and this DebugLib instance will produce output on a *different* UART. +# +# This instance is suitable for modules that can only run from RAM (except +# DXE_RUNTIME_DRIVER). +# +# Copyright (C) Red Hat +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 1.27 + BASE_NAME = DebugLibFdtPL011UartRam + FILE_GUID = 0584DE55-9C4C-49C1-ADA0-F62C9C1F3600 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = DebugLib|DXE_CORE SMM_CORE MM_CORE_STANDALONE DXE_DRIVER DXE_SMM_DRIVER SMM_DRIVER MM_STANDALONE UEFI_DRIVER UEFI_APPLICATION + CONSTRUCTOR = DebugLibFdtPL011UartRamConstructor + +[Sources] + DebugLib.c + Ram.c + Ram.h + RamNonRuntime.c + Write.h + +[Packages] + ArmPlatformPkg/ArmPlatformPkg.dec + ArmVirtPkg/ArmVirtPkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugPrintErrorLevelLib + HobLib # Ram.c + PL011UartLib + PcdLib + PrintLib + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdDebugClearMemoryValue + gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask + gEfiMdePkgTokenSpaceGuid.PcdFixedDebugPrintErrorLevel + +[FixedPcd] + gArmPlatformTokenSpaceGuid.PL011UartClkInHz + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity + gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits + +[Guids] + gEarlyPL011BaseAddressGuid # Ram.c diff --git a/ArmVirtPkg/Library/DebugLibFdtPL011Uart/Ram.c b/ArmVirtPkg/Library/DebugLibFdtPL011Uart/Ram.c new file mode 100644 index 0000000000..bc5be015bd --- /dev/null +++ b/ArmVirtPkg/Library/DebugLibFdtPL011Uart/Ram.c @@ -0,0 +1,124 @@ +/** @file + Define DebugLibFdtPL011UartWrite() for modules that can only run from RAM. + + Copyright (C) Red Hat + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Ram.h" +#include "Write.h" + +UINTN mDebugLibFdtPL011UartAddress; +RETURN_STATUS mDebugLibFdtPL011UartPermanentStatus = RETURN_SUCCESS; + +/** + Statefully initialize both the library instance and the debug PL011 UART. +**/ +STATIC +RETURN_STATUS +Initialize ( + VOID + ) +{ + CONST VOID *Hob; + CONST EARLY_PL011_BASE_ADDRESS *UartBase; + RETURN_STATUS Status; + UINTN DebugAddress; + UINT64 BaudRate; + UINT32 ReceiveFifoDepth; + EFI_PARITY_TYPE Parity; + UINT8 DataBits; + EFI_STOP_BITS_TYPE StopBits; + + if (mDebugLibFdtPL011UartAddress != 0) { + return RETURN_SUCCESS; + } + + if (RETURN_ERROR (mDebugLibFdtPL011UartPermanentStatus)) { + return mDebugLibFdtPL011UartPermanentStatus; + } + + Hob = GetFirstGuidHob (&gEarlyPL011BaseAddressGuid); + if ((Hob == NULL) || (GET_GUID_HOB_DATA_SIZE (Hob) != sizeof *UartBase)) { + Status = RETURN_NOT_FOUND; + goto Failed; + } + + UartBase = GET_GUID_HOB_DATA (Hob); + + DebugAddress = (UINTN)UartBase->DebugAddress; + if (DebugAddress == 0) { + Status = RETURN_NOT_FOUND; + goto Failed; + } + + BaudRate = (UINTN)PcdGet64 (PcdUartDefaultBaudRate); + ReceiveFifoDepth = 0; // Use the default value for Fifo depth + Parity = (EFI_PARITY_TYPE)PcdGet8 (PcdUartDefaultParity); + DataBits = PcdGet8 (PcdUartDefaultDataBits); + StopBits = (EFI_STOP_BITS_TYPE)PcdGet8 (PcdUartDefaultStopBits); + + Status = PL011UartInitializePort ( + DebugAddress, + FixedPcdGet32 (PL011UartClkInHz), + &BaudRate, + &ReceiveFifoDepth, + &Parity, + &DataBits, + &StopBits + ); + if (RETURN_ERROR (Status)) { + goto Failed; + } + + mDebugLibFdtPL011UartAddress = DebugAddress; + return RETURN_SUCCESS; + +Failed: + mDebugLibFdtPL011UartPermanentStatus = Status; + return Status; +} + +/** + (Copied from SerialPortWrite() in "MdePkg/Include/Library/SerialPortLib.h" at + commit c4547aefb3d0, with the Buffer non-nullity assertion removed:) + + Write data from buffer to serial device. + + Writes NumberOfBytes data bytes from Buffer to the serial device. + The number of bytes actually written to the serial device is returned. + If the return value is less than NumberOfBytes, then the write operation failed. + If NumberOfBytes is zero, then return 0. + + @param Buffer Pointer to the data buffer to be written. + @param NumberOfBytes Number of bytes to written to the serial device. + + @retval 0 NumberOfBytes is 0. + @retval >0 The number of bytes written to the serial device. + If this value is less than NumberOfBytes, then the write operation failed. +**/ +UINTN +DebugLibFdtPL011UartWrite ( + IN UINT8 *Buffer, + IN UINTN NumberOfBytes + ) +{ + RETURN_STATUS Status; + + Status = Initialize (); + if (RETURN_ERROR (Status)) { + return 0; + } + + return PL011UartWrite (mDebugLibFdtPL011UartAddress, Buffer, NumberOfBytes); +} diff --git a/ArmVirtPkg/Library/DebugLibFdtPL011Uart/Ram.h b/ArmVirtPkg/Library/DebugLibFdtPL011Uart/Ram.h new file mode 100644 index 0000000000..8c1ef52b4d --- /dev/null +++ b/ArmVirtPkg/Library/DebugLibFdtPL011Uart/Ram.h @@ -0,0 +1,18 @@ +/** @file + Declare the variables that modules that can only run from RAM use for + remembering initialization status. + + Copyright (C) Red Hat + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef DEBUG_LIB_FDT_PL011_UART_RAM_H_ +#define DEBUG_LIB_FDT_PL011_UART_RAM_H_ + +#include + +extern UINTN mDebugLibFdtPL011UartAddress; +extern RETURN_STATUS mDebugLibFdtPL011UartPermanentStatus; + +#endif diff --git a/ArmVirtPkg/Library/DebugLibFdtPL011Uart/RamNonRuntime.c b/ArmVirtPkg/Library/DebugLibFdtPL011Uart/RamNonRuntime.c new file mode 100644 index 0000000000..715d3400dd --- /dev/null +++ b/ArmVirtPkg/Library/DebugLibFdtPL011Uart/RamNonRuntime.c @@ -0,0 +1,27 @@ +/** @file + Provide an empty lib instance constructor for modules that can only run from + RAM but are not DXE_RUNTIME_DRIVER modules. + + This ensures that e.g. any HobLib constructor is ordered correctly. (The + DXE_CORE calls constructors late, but the DXE_CORE HobLib instance needs no + construction anyway.) + + Copyright (C) Red Hat + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include + +/** + Empty library instance constructor, only for ensuring the connectivity of the + constructor dependency graph. +**/ +RETURN_STATUS +EFIAPI +DebugLibFdtPL011UartRamConstructor ( + VOID + ) +{ + return RETURN_SUCCESS; +}