diff options
author | Chao Li <lichao@loongson.cn> | 2024-01-16 20:26:22 +0800 |
---|---|---|
committer | Liming Gao <gaoliming@byosoft.com.cn> | 2024-02-06 23:51:47 +0800 |
commit | 0cca97e0a839eac1a333193d7811a32ad5c44c5f (patch) | |
tree | 19983fd222ac89d530ed9ef172713ea8187117e5 /OvmfPkg | |
parent | 5a3788bfca0b305044704bdb02d582f49974c9f3 (diff) | |
download | edk2-0cca97e0a839eac1a333193d7811a32ad5c44c5f.zip edk2-0cca97e0a839eac1a333193d7811a32ad5c44c5f.tar.gz edk2-0cca97e0a839eac1a333193d7811a32ad5c44c5f.tar.bz2 |
ArmVirtPkg: Move the FdtSerialPortAddressLib to OvmfPkg
Move the FdtSerialPortAddressLib to Ovmfpkg so that other ARCH can
easily use it.
Build-tested only (with "ArmVirtQemu.dsc and OvmfPkgX64.dsc").
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4584
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Sami Mujawar <sami.mujawar@arm.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Diffstat (limited to 'OvmfPkg')
-rw-r--r-- | OvmfPkg/Include/Library/FdtSerialPortAddressLib.h | 83 | ||||
-rw-r--r-- | OvmfPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.c | 256 | ||||
-rw-r--r-- | OvmfPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.inf | 27 | ||||
-rw-r--r-- | OvmfPkg/OvmfPkg.dec | 4 |
4 files changed, 370 insertions, 0 deletions
diff --git a/OvmfPkg/Include/Library/FdtSerialPortAddressLib.h b/OvmfPkg/Include/Library/FdtSerialPortAddressLib.h new file mode 100644 index 0000000..3d4c911 --- /dev/null +++ b/OvmfPkg/Include/Library/FdtSerialPortAddressLib.h @@ -0,0 +1,83 @@ +/** @file
+ Determine the base addresses of serial ports from the Device Tree.
+
+ Copyright (C) Red Hat
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef FDT_SERIAL_PORT_ADDRESS_LIB_H_
+#define FDT_SERIAL_PORT_ADDRESS_LIB_H_
+
+#include <Base.h>
+
+typedef struct {
+ UINTN NumberOfPorts;
+ UINT64 BaseAddress[2];
+} FDT_SERIAL_PORTS;
+
+/**
+ Collect the first ARRAY_SIZE (Ports->BaseAddress) serial ports into Ports from
+ DeviceTree.
+
+ @param[in] DeviceTree The flat device tree (FDT) to scan.
+
+ @param[in] Compatible Look for Compatible in the "compatible" property of the
+ scanned nodes.
+
+ @param[out] Ports On successful return, Ports->NumberOfPorts contains the
+ number of serial ports found; it is (a) positive and
+ (b) at most ARRAY_SIZE (Ports->BaseAddress). If the FDT
+ had more serial ports, those are not reported. On
+ error, the contents of Ports are indeterminate.
+
+ @retval RETURN_INVALID_PARAMETER DeviceTree does not point to a valid FDT
+ header.
+
+ @retval RETURN_NOT_FOUND No compatible and enabled serial port has
+ been found.
+
+ @retval RETURN_SUCCESS At least one compatible and enabled serial
+ port has been found; Ports has been filled
+ in.
+**/
+RETURN_STATUS
+EFIAPI
+FdtSerialGetPorts (
+ IN CONST VOID *DeviceTree,
+ IN CONST CHAR8 *Compatible,
+ OUT FDT_SERIAL_PORTS *Ports
+ );
+
+/**
+ Fetch the base address of the serial port identified in the "stdout-path"
+ property of the "/chosen" node in DeviceTree.
+
+ @param[in] DeviceTree The flat device tree (FDT) to scan.
+
+ @param[out] BaseAddress On success, the base address of the preferred serial
+ port (to be used as console). On error, BaseAddress
+ is not modified.
+
+ @retval RETURN_INVALID_PARAMETER DeviceTree does not point to a valid FDT
+ header.
+
+ @retval RETURN_NOT_FOUND No enabled console port has been found.
+
+ @retval RETURN_PROTOCOL_ERROR The first (or only) node path in the
+ "stdout-path" property is an empty string.
+
+ @retval RETURN_PROTOCOL_ERROR The console port has been found in the FDT,
+ but its base address is not correctly
+ represented.
+
+ @retval RETURN_SUCCESS BaseAddress has been populated.
+**/
+RETURN_STATUS
+EFIAPI
+FdtSerialGetConsolePort (
+ IN CONST VOID *DeviceTree,
+ OUT UINT64 *BaseAddress
+ );
+
+#endif
diff --git a/OvmfPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.c b/OvmfPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.c new file mode 100644 index 0000000..f6508e0 --- /dev/null +++ b/OvmfPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.c @@ -0,0 +1,256 @@ +/** @file
+ Determine the base addresses of serial ports from the Device Tree.
+
+ Copyright (C) Red Hat
+ Copyright (c) 2011 - 2023, Arm Ltd. All rights reserved.<BR>
+ Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
+ Copyright (c) 2014 - 2020, Linaro Ltd. All rights reserved.<BR>
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/FdtSerialPortAddressLib.h>
+#include <libfdt.h>
+
+/**
+ Read the "reg" property of Node in DeviceTree as a UINT64 base address.
+
+ @param[in] DeviceTree The flat device tree (FDT) to scan.
+
+ @param[in] Node The node to read the "reg" property of.
+
+ @param[out] BaseAddress On success, the base address read out of Node's "reg"
+ property. On error, not modified.
+
+ @retval RETURN_DEVICE_ERROR Node has a "status" property with value
+ different from "okay".
+
+ @retval RETURN_NOT_FOUND Node does not have a "reg" property.
+
+ @retval RETURN_BAD_BUFFER_SIZE The size of Node's "reg" property is not 16
+ bytes.
+
+ @retval RETURN_SUCCESS BaseAddress has been populated.
+**/
+STATIC
+RETURN_STATUS
+GetBaseAddress (
+ IN CONST VOID *DeviceTree,
+ IN INT32 Node,
+ OUT UINT64 *BaseAddress
+ )
+{
+ CONST CHAR8 *NodeStatus;
+ CONST VOID *RegProp;
+ INT32 PropSize;
+
+ NodeStatus = fdt_getprop (DeviceTree, Node, "status", NULL);
+ if ((NodeStatus != NULL) && (AsciiStrCmp (NodeStatus, "okay") != 0)) {
+ return RETURN_DEVICE_ERROR;
+ }
+
+ RegProp = fdt_getprop (DeviceTree, Node, "reg", &PropSize);
+ if (RegProp == NULL) {
+ return RETURN_NOT_FOUND;
+ }
+
+ if (PropSize != 16) {
+ return RETURN_BAD_BUFFER_SIZE;
+ }
+
+ *BaseAddress = fdt64_to_cpu (ReadUnaligned64 (RegProp));
+ return RETURN_SUCCESS;
+}
+
+/**
+ Collect the first ARRAY_SIZE (Ports->BaseAddress) serial ports into Ports from
+ DeviceTree.
+
+ @param[in] DeviceTree The flat device tree (FDT) to scan.
+
+ @param[in] Compatible Look for Compatible in the "compatible" property of the
+ scanned nodes.
+
+ @param[out] Ports On successful return, Ports->NumberOfPorts contains the
+ number of serial ports found; it is (a) positive and
+ (b) at most ARRAY_SIZE (Ports->BaseAddress). If the FDT
+ had more serial ports, those are not reported. On
+ error, the contents of Ports are indeterminate.
+
+ @retval RETURN_INVALID_PARAMETER DeviceTree does not point to a valid FDT
+ header.
+
+ @retval RETURN_NOT_FOUND No compatible and enabled serial port has
+ been found.
+
+ @retval RETURN_SUCCESS At least one compatible and enabled serial
+ port has been found; Ports has been filled
+ in.
+**/
+RETURN_STATUS
+EFIAPI
+FdtSerialGetPorts (
+ IN CONST VOID *DeviceTree,
+ IN CONST CHAR8 *Compatible,
+ OUT FDT_SERIAL_PORTS *Ports
+ )
+{
+ INT32 Node;
+
+ if (fdt_check_header (DeviceTree) != 0) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ Ports->NumberOfPorts = 0;
+ Node = fdt_next_node (DeviceTree, 0, NULL);
+ while ((Node > 0) &&
+ (Ports->NumberOfPorts < ARRAY_SIZE (Ports->BaseAddress)))
+ {
+ CONST CHAR8 *CompatProp;
+ INT32 PropSize;
+
+ CompatProp = fdt_getprop (DeviceTree, Node, "compatible", &PropSize);
+ if (CompatProp != NULL) {
+ CONST CHAR8 *CompatItem;
+
+ CompatItem = CompatProp;
+ while ((CompatItem < CompatProp + PropSize) &&
+ (AsciiStrCmp (CompatItem, Compatible) != 0))
+ {
+ CompatItem += AsciiStrLen (CompatItem) + 1;
+ }
+
+ if (CompatItem < CompatProp + PropSize) {
+ RETURN_STATUS Status;
+ UINT64 BaseAddress;
+
+ Status = GetBaseAddress (DeviceTree, Node, &BaseAddress);
+ if (!RETURN_ERROR (Status)) {
+ Ports->BaseAddress[Ports->NumberOfPorts++] = BaseAddress;
+ }
+ }
+ }
+
+ Node = fdt_next_node (DeviceTree, Node, NULL);
+ }
+
+ return Ports->NumberOfPorts > 0 ? RETURN_SUCCESS : RETURN_NOT_FOUND;
+}
+
+/**
+ Fetch the base address of the serial port identified in the "stdout-path"
+ property of the "/chosen" node in DeviceTree.
+
+ @param[in] DeviceTree The flat device tree (FDT) to scan.
+
+ @param[out] BaseAddress On success, the base address of the preferred serial
+ port (to be used as console). On error, BaseAddress
+ is not modified.
+
+ @retval RETURN_INVALID_PARAMETER DeviceTree does not point to a valid FDT
+ header.
+
+ @retval RETURN_NOT_FOUND No enabled console port has been found.
+
+ @retval RETURN_PROTOCOL_ERROR The first (or only) node path in the
+ "stdout-path" property is an empty string.
+
+ @retval RETURN_PROTOCOL_ERROR The console port has been found in the FDT,
+ but its base address is not correctly
+ represented.
+
+ @retval RETURN_SUCCESS BaseAddress has been populated.
+**/
+RETURN_STATUS
+EFIAPI
+FdtSerialGetConsolePort (
+ IN CONST VOID *DeviceTree,
+ OUT UINT64 *BaseAddress
+ )
+{
+ INT32 ChosenNode;
+ CONST CHAR8 *StdoutPathProp;
+ INT32 PropSize;
+ CONST CHAR8 *StdoutPathEnd;
+ UINTN StdoutPathLength;
+ INT32 ConsoleNode;
+ RETURN_STATUS Status;
+
+ if (fdt_check_header (DeviceTree) != 0) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ ChosenNode = fdt_path_offset (DeviceTree, "/chosen");
+ if (ChosenNode < 0) {
+ return RETURN_NOT_FOUND;
+ }
+
+ StdoutPathProp = fdt_getprop (
+ DeviceTree,
+ ChosenNode,
+ "stdout-path",
+ &PropSize
+ );
+ if (StdoutPathProp == NULL) {
+ return RETURN_NOT_FOUND;
+ }
+
+ //
+ // If StdoutPathProp contains a colon (":"), then the colon terminates the
+ // path we're interested in.
+ //
+ StdoutPathEnd = AsciiStrStr (StdoutPathProp, ":");
+ if (StdoutPathEnd == NULL) {
+ StdoutPathLength = PropSize - 1;
+ } else {
+ StdoutPathLength = StdoutPathEnd - StdoutPathProp;
+ }
+
+ if (StdoutPathLength == 0) {
+ return RETURN_PROTOCOL_ERROR;
+ }
+
+ if (StdoutPathProp[0] == '/') {
+ //
+ // StdoutPathProp starts with an absolute node path.
+ //
+ ConsoleNode = fdt_path_offset_namelen (
+ DeviceTree,
+ StdoutPathProp,
+ (INT32)StdoutPathLength
+ );
+ } else {
+ //
+ // StdoutPathProp starts with an alias.
+ //
+ CONST CHAR8 *ResolvedStdoutPath;
+
+ ResolvedStdoutPath = fdt_get_alias_namelen (
+ DeviceTree,
+ StdoutPathProp,
+ (INT32)StdoutPathLength
+ );
+ if (ResolvedStdoutPath == NULL) {
+ return RETURN_NOT_FOUND;
+ }
+
+ ConsoleNode = fdt_path_offset (DeviceTree, ResolvedStdoutPath);
+ }
+
+ if (ConsoleNode < 0) {
+ return RETURN_NOT_FOUND;
+ }
+
+ Status = GetBaseAddress (DeviceTree, ConsoleNode, BaseAddress);
+ switch (Status) {
+ case RETURN_NOT_FOUND:
+ case RETURN_BAD_BUFFER_SIZE:
+ return RETURN_PROTOCOL_ERROR;
+ case RETURN_SUCCESS:
+ return RETURN_SUCCESS;
+ default:
+ return RETURN_NOT_FOUND;
+ }
+}
diff --git a/OvmfPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.inf b/OvmfPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.inf new file mode 100644 index 0000000..e27742e --- /dev/null +++ b/OvmfPkg/Library/FdtSerialPortAddressLib/FdtSerialPortAddressLib.inf @@ -0,0 +1,27 @@ +## @file
+# Determine the base addresses of serial ports from the Device Tree.
+#
+# Copyright (C) Red Hat
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 1.27
+ BASE_NAME = FdtSerialPortAddressLib
+ FILE_GUID = AEBE813B-25EA-40E5-95C4-2B864FE1E951
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = FdtSerialPortAddressLib
+
+[Sources]
+ FdtSerialPortAddressLib.c
+
+[Packages]
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ FdtLib
diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec index 7bc2bf1..13e69e6 100644 --- a/OvmfPkg/OvmfPkg.dec +++ b/OvmfPkg/OvmfPkg.dec @@ -29,6 +29,10 @@ ## @libraryclass Verify blobs read from the VMM
BlobVerifierLib|Include/Library/BlobVerifierLib.h
+ ## @libraryclass FdtSerialPortAddressLib
+ #
+ FdtSerialPortAddressLib|Include/Library/FdtSerialPortAddressLib.h
+
## @libraryclass Loads and boots a Linux kernel image
#
LoadLinuxLib|Include/Library/LoadLinuxLib.h
|