This implements a new DXE driver FdtClientDxe to produce the FDT client protocol based on a device tree image supplied by the virt host.
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ard Biesheuvel <[email protected]> --- ArmVirtPkg/FdtClientDxe/FdtClientDxe.c | 236 ++++++++++++++++++++ ArmVirtPkg/FdtClientDxe/FdtClientDxe.inf | 48 ++++ 2 files changed, 284 insertions(+) diff --git a/ArmVirtPkg/FdtClientDxe/FdtClientDxe.c b/ArmVirtPkg/FdtClientDxe/FdtClientDxe.c new file mode 100644 index 000000000000..716194ef798a --- /dev/null +++ b/ArmVirtPkg/FdtClientDxe/FdtClientDxe.c @@ -0,0 +1,236 @@ +/** @file +* FDT client driver +* +* Copyright (c) 2016, Linaro Ltd. 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 <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/UefiLib.h> +#include <Library/UefiDriverEntryPoint.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/HobLib.h> +#include <libfdt.h> + +#include <Guid/Fdt.h> +#include <Guid/FdtHob.h> + +#include <Protocol/FdtClient.h> + +STATIC VOID *mDeviceTreeBase; + +STATIC +EFI_STATUS +GetNodeProperty ( + IN FDT_CLIENT_PROTOCOL *This, + IN INT32 Node, + IN CONST CHAR8 *PropertyName, + OUT CONST VOID **Prop, + OUT UINTN *PropSize OPTIONAL + ) +{ + INT32 Len; + + ASSERT (mDeviceTreeBase != NULL); + + *Prop = fdt_getprop (mDeviceTreeBase, Node, PropertyName, &Len); + if (*Prop == NULL) { + return EFI_NOT_FOUND; + } + + if (PropSize != NULL) { + *PropSize = Len; + } + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +SetNodeProperty ( + IN FDT_CLIENT_PROTOCOL *This, + IN INT32 Node, + IN CONST CHAR8 *PropertyName, + IN CONST VOID *Prop, + IN UINTN PropSize + ) +{ + INT32 Ret; + + ASSERT (mDeviceTreeBase != NULL); + + Ret = fdt_setprop (mDeviceTreeBase, Node, PropertyName, Prop, (UINT32)PropSize); + if (Ret != 0) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +FindCompatibleNode ( + IN FDT_CLIENT_PROTOCOL *This, + IN CONST CHAR8 *CompatibleString, + OUT INT32 *Node + ) +{ + INT32 NextNode, PrevNode; + CONST CHAR8 *Type, *Compatible; + INT32 Len; + + ASSERT (mDeviceTreeBase != NULL); + + if (Node == NULL) { + return EFI_INVALID_PARAMETER; + } + + for (PrevNode = 0;; PrevNode = NextNode) { + NextNode = fdt_next_node (mDeviceTreeBase, PrevNode, NULL); + if (NextNode < 0) { + break; + } + + Type = fdt_getprop (mDeviceTreeBase, NextNode, "compatible", &Len); + if (Type == NULL) { + continue; + } + + // + // A 'compatible' node may contain a sequence of NULL terminated + // compatible strings so check each one + // + for (Compatible = Type; Compatible < Type + Len && *Compatible; + Compatible += 1 + AsciiStrLen (Compatible)) { + if (AsciiStrCmp (CompatibleString, Compatible) == 0) { + *Node = NextNode; + return EFI_SUCCESS; + } + } + } + return EFI_NOT_FOUND; +} + +STATIC +EFI_STATUS +EFIAPI +FindCompatibleNodeProperty ( + IN FDT_CLIENT_PROTOCOL *This, + IN CONST CHAR8 *CompatibleString, + IN CONST CHAR8 *PropertyName, + OUT CONST VOID **Prop, + OUT UINTN *PropSize OPTIONAL + ) +{ + EFI_STATUS Status; + INT32 Node; + + Status = FindCompatibleNode (This, CompatibleString, &Node); + if (EFI_ERROR (Status)) { + return Status; + } + + return GetNodeProperty (This, Node, PropertyName, Prop, PropSize); +} + +STATIC +EFI_STATUS +EFIAPI +FindCompatibleNodeReg ( + IN FDT_CLIENT_PROTOCOL *This, + IN CONST CHAR8 *CompatibleString, + OUT CONST VOID **Reg, + OUT UINTN *RegElemSize, + OUT UINTN *RegSize + ) +{ + EFI_STATUS Status; + + // + // Get the 'reg' property of this node. For now, we will assume + // 8 byte quantities for base and size, respectively. + // TODO use #cells root properties instead + // + Status = FindCompatibleNodeProperty (This, CompatibleString, "reg", Reg, RegSize); + if (EFI_ERROR (Status)) { + return Status; + } + + *RegElemSize = 8; + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +GetChosenNode ( + IN FDT_CLIENT_PROTOCOL *This, + OUT INT32 *Node + ) +{ + INT32 NewNode; + + ASSERT (mDeviceTreeBase != NULL); + + NewNode = fdt_path_offset (mDeviceTreeBase, "/chosen"); + if (NewNode < 0) { + NewNode = fdt_add_subnode (mDeviceTreeBase, 0, "/chosen"); + } + + if (NewNode < 0) { + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + +STATIC FDT_CLIENT_PROTOCOL mFdtClientProtocol = { + GetNodeProperty, + SetNodeProperty, + FindCompatibleNode, + FindCompatibleNodeProperty, + FindCompatibleNodeReg, + GetChosenNode, +}; + +EFI_STATUS +EFIAPI +InitializeFdtClientDxe ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + VOID *Hob; + VOID *DeviceTreeBase; + + Hob = GetFirstGuidHob(&gFdtHobGuid); + if (Hob == NULL || GET_GUID_HOB_DATA_SIZE (Hob) != sizeof (UINT64)) { + return EFI_NOT_FOUND; + } + DeviceTreeBase = (VOID *)(UINTN)*(UINT64 *)GET_GUID_HOB_DATA (Hob); + + if (fdt_check_header (DeviceTreeBase) != 0) { + DEBUG ((EFI_D_ERROR, "%a: No DTB found @ 0x%p\n", __FUNCTION__, DeviceTreeBase)); + return EFI_NOT_FOUND; + } + + mDeviceTreeBase = DeviceTreeBase; + + DEBUG ((EFI_D_INFO, "%a: DTB @ 0x%p\n", __FUNCTION__, mDeviceTreeBase)); + + return gBS->InstallProtocolInterface ( + &ImageHandle, + &gFdtClientProtocolGuid, + EFI_NATIVE_INTERFACE, + &mFdtClientProtocol + ); +} diff --git a/ArmVirtPkg/FdtClientDxe/FdtClientDxe.inf b/ArmVirtPkg/FdtClientDxe/FdtClientDxe.inf new file mode 100644 index 000000000000..55a1e680ce7c --- /dev/null +++ b/ArmVirtPkg/FdtClientDxe/FdtClientDxe.inf @@ -0,0 +1,48 @@ +## @file +# FDT client driver +# +# Copyright (c) 2016, Linaro Ltd. 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. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = FdtClientDxe + FILE_GUID = 9A871B00-1C16-4F61-8D2C-93B6654B5AD6 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = InitializeFdtClientDxe + +[Sources] + FdtClientDxe.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + ArmVirtPkg/ArmVirtPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + BaseLib + PcdLib + UefiDriverEntryPoint + FdtLib + HobLib + UefiBootServicesTableLib + +[Protocols] + gFdtClientProtocolGuid + +[Guids] + gFdtHobGuid + +[Depex] + TRUE -- 2.5.0 _______________________________________________ edk2-devel mailing list [email protected] https://lists.01.org/mailman/listinfo/edk2-devel

