X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=ArmVirtPkg%2FFdtClientDxe%2FFdtClientDxe.c;h=5bfde381ecd0d53996272771bdee6ebe5d5ada96;hp=9c589e620cb40c7d542a85d4b8e26c05d9db2d7a;hb=32f5975770c309723ebb17642f89bbf9670955fd;hpb=30740795ef0e795bb7d7b4dd87e4a8a73e4e9cc4 diff --git a/ArmVirtPkg/FdtClientDxe/FdtClientDxe.c b/ArmVirtPkg/FdtClientDxe/FdtClientDxe.c index 9c589e620c..5bfde381ec 100644 --- a/ArmVirtPkg/FdtClientDxe/FdtClientDxe.c +++ b/ArmVirtPkg/FdtClientDxe/FdtClientDxe.c @@ -20,7 +20,9 @@ #include #include +#include #include +#include #include @@ -28,6 +30,7 @@ STATIC VOID *mDeviceTreeBase; STATIC EFI_STATUS +EFIAPI GetNodeProperty ( IN FDT_CLIENT_PROTOCOL *This, IN INT32 Node, @@ -54,6 +57,7 @@ GetNodeProperty ( STATIC EFI_STATUS +EFIAPI SetNodeProperty ( IN FDT_CLIENT_PROTOCOL *This, IN INT32 Node, @@ -74,6 +78,33 @@ SetNodeProperty ( return EFI_SUCCESS; } +STATIC +BOOLEAN +IsNodeEnabled ( + INT32 Node + ) +{ + CONST CHAR8 *NodeStatus; + INT32 Len; + + // + // A missing status property implies 'ok' so ignore any errors that + // may occur here. If the status property is present, check whether + // it is set to 'ok' or 'okay', anything else is treated as 'disabled'. + // + NodeStatus = fdt_getprop (mDeviceTreeBase, Node, "status", &Len); + if (NodeStatus == NULL) { + return TRUE; + } + if (Len >= 5 && AsciiStrCmp (NodeStatus, "okay") == 0) { + return TRUE; + } + if (Len >= 3 && AsciiStrCmp (NodeStatus, "ok") == 0) { + return TRUE; + } + return FALSE; +} + STATIC EFI_STATUS EFIAPI @@ -97,6 +128,10 @@ FindNextCompatibleNode ( break; } + if (!IsNodeEnabled (Next)) { + continue; + } + Type = fdt_getprop (mDeviceTreeBase, Next, "compatible", &Len); if (Type == NULL) { continue; @@ -158,7 +193,8 @@ FindCompatibleNodeReg ( IN FDT_CLIENT_PROTOCOL *This, IN CONST CHAR8 *CompatibleString, OUT CONST VOID **Reg, - OUT UINT32 *RegElemSize, + OUT UINTN *AddressCells, + OUT UINTN *SizeCells, OUT UINT32 *RegSize ) { @@ -177,20 +213,100 @@ FindCompatibleNodeReg ( return Status; } - if ((*RegSize % 8) != 0) { + if ((*RegSize % 16) != 0) { DEBUG ((EFI_D_ERROR, "%a: '%a' compatible node has invalid 'reg' property (size == 0x%x)\n", __FUNCTION__, CompatibleString, *RegSize)); return EFI_NOT_FOUND; } - *RegElemSize = 8; + *AddressCells = 2; + *SizeCells = 2; return EFI_SUCCESS; } STATIC EFI_STATUS +EFIAPI +FindNextMemoryNodeReg ( + IN FDT_CLIENT_PROTOCOL *This, + IN INT32 PrevNode, + OUT INT32 *Node, + OUT CONST VOID **Reg, + OUT UINTN *AddressCells, + OUT UINTN *SizeCells, + OUT UINT32 *RegSize + ) +{ + INT32 Prev, Next; + CONST CHAR8 *DeviceType; + INT32 Len; + EFI_STATUS Status; + + ASSERT (mDeviceTreeBase != NULL); + ASSERT (Node != NULL); + + for (Prev = PrevNode;; Prev = Next) { + Next = fdt_next_node (mDeviceTreeBase, Prev, NULL); + if (Next < 0) { + break; + } + + if (!IsNodeEnabled (Next)) { + DEBUG ((DEBUG_WARN, "%a: ignoring disabled memory node\n", __FUNCTION__)); + continue; + } + + DeviceType = fdt_getprop (mDeviceTreeBase, Next, "device_type", &Len); + if (DeviceType != NULL && AsciiStrCmp (DeviceType, "memory") == 0) { + // + // Get the 'reg' property of this memory node. For now, we will assume + // 8 byte quantities for base and size, respectively. + // TODO use #cells root properties instead + // + Status = GetNodeProperty (This, Next, "reg", Reg, RegSize); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_WARN, + "%a: ignoring memory node with no 'reg' property\n", + __FUNCTION__)); + continue; + } + if ((*RegSize % 16) != 0) { + DEBUG ((EFI_D_WARN, + "%a: ignoring memory node with invalid 'reg' property (size == 0x%x)\n", + __FUNCTION__, *RegSize)); + continue; + } + + *Node = Next; + *AddressCells = 2; + *SizeCells = 2; + return EFI_SUCCESS; + } + } + return EFI_NOT_FOUND; +} + +STATIC +EFI_STATUS +EFIAPI +FindMemoryNodeReg ( + IN FDT_CLIENT_PROTOCOL *This, + OUT INT32 *Node, + OUT CONST VOID **Reg, + OUT UINTN *AddressCells, + OUT UINTN *SizeCells, + OUT UINT32 *RegSize + ) +{ + return FindNextMemoryNodeReg (This, 0, Node, Reg, AddressCells, SizeCells, + RegSize); +} + +STATIC +EFI_STATUS +EFIAPI GetOrInsertChosenNode ( IN FDT_CLIENT_PROTOCOL *This, OUT INT32 *Node @@ -222,9 +338,45 @@ STATIC FDT_CLIENT_PROTOCOL mFdtClientProtocol = { FindNextCompatibleNode, FindCompatibleNodeProperty, FindCompatibleNodeReg, + FindMemoryNodeReg, + FindNextMemoryNodeReg, GetOrInsertChosenNode, }; +STATIC +VOID +EFIAPI +OnPlatformHasDeviceTree ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + VOID *Interface; + VOID *DeviceTreeBase; + + Status = gBS->LocateProtocol ( + &gEdkiiPlatformHasDeviceTreeGuid, + NULL, // Registration + &Interface + ); + if (EFI_ERROR (Status)) { + return; + } + + DeviceTreeBase = Context; + DEBUG (( + DEBUG_INFO, + "%a: exposing DTB @ 0x%p to OS\n", + __FUNCTION__, + DeviceTreeBase + )); + Status = gBS->InstallConfigurationTable (&gFdtTableGuid, DeviceTreeBase); + ASSERT_EFI_ERROR (Status); + + gBS->CloseEvent (Event); +} + EFI_STATUS EFIAPI InitializeFdtClientDxe ( @@ -234,6 +386,9 @@ InitializeFdtClientDxe ( { VOID *Hob; VOID *DeviceTreeBase; + EFI_STATUS Status; + EFI_EVENT PlatformHasDeviceTreeEvent; + VOID *Registration; Hob = GetFirstGuidHob (&gFdtHobGuid); if (Hob == NULL || GET_GUID_HOB_DATA_SIZE (Hob) != sizeof (UINT64)) { @@ -251,6 +406,65 @@ InitializeFdtClientDxe ( DEBUG ((EFI_D_INFO, "%a: DTB @ 0x%p\n", __FUNCTION__, mDeviceTreeBase)); - return gBS->InstallProtocolInterface (&ImageHandle, &gFdtClientProtocolGuid, - EFI_NATIVE_INTERFACE, &mFdtClientProtocol); + // + // Register a protocol notify for the EDKII Platform Has Device Tree + // Protocol. + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + OnPlatformHasDeviceTree, + DeviceTreeBase, // Context + &PlatformHasDeviceTreeEvent + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: CreateEvent(): %r\n", __FUNCTION__, Status)); + return Status; + } + + Status = gBS->RegisterProtocolNotify ( + &gEdkiiPlatformHasDeviceTreeGuid, + PlatformHasDeviceTreeEvent, + &Registration + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a: RegisterProtocolNotify(): %r\n", + __FUNCTION__, + Status + )); + goto CloseEvent; + } + + // + // Kick the event; the protocol could be available already. + // + Status = gBS->SignalEvent (PlatformHasDeviceTreeEvent); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: SignalEvent(): %r\n", __FUNCTION__, Status)); + goto CloseEvent; + } + + Status = gBS->InstallProtocolInterface ( + &ImageHandle, + &gFdtClientProtocolGuid, + EFI_NATIVE_INTERFACE, + &mFdtClientProtocol + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a: InstallProtocolInterface(): %r\n", + __FUNCTION__, + Status + )); + goto CloseEvent; + } + + return Status; + +CloseEvent: + gBS->CloseEvent (PlatformHasDeviceTreeEvent); + return Status; }