summaryrefslogtreecommitdiff
path: root/OvmfPkg/Fdt/VirtioFdtDxe/VirtioFdtDxe.c
diff options
context:
space:
mode:
Diffstat (limited to 'OvmfPkg/Fdt/VirtioFdtDxe/VirtioFdtDxe.c')
-rw-r--r--OvmfPkg/Fdt/VirtioFdtDxe/VirtioFdtDxe.c118
1 files changed, 118 insertions, 0 deletions
diff --git a/OvmfPkg/Fdt/VirtioFdtDxe/VirtioFdtDxe.c b/OvmfPkg/Fdt/VirtioFdtDxe/VirtioFdtDxe.c
new file mode 100644
index 0000000..9625693
--- /dev/null
+++ b/OvmfPkg/Fdt/VirtioFdtDxe/VirtioFdtDxe.c
@@ -0,0 +1,118 @@
+/** @file
+* Virtio FDT client protocol driver for virtio,mmio DT node
+*
+* Copyright (c) 2014 - 2016, Linaro Ltd. All rights reserved.<BR>
+*
+* SPDX-License-Identifier: BSD-2-Clause-Patent
+*
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/VirtioMmioDeviceLib.h>
+
+#include <Guid/VirtioMmioTransport.h>
+
+#include <Protocol/FdtClient.h>
+
+#pragma pack (1)
+typedef struct {
+ VENDOR_DEVICE_PATH Vendor;
+ UINT64 PhysBase;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} VIRTIO_TRANSPORT_DEVICE_PATH;
+#pragma pack ()
+
+EFI_STATUS
+EFIAPI
+InitializeVirtioFdtDxe (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status, FindNodeStatus;
+ FDT_CLIENT_PROTOCOL *FdtClient;
+ INT32 Node;
+ CONST UINT64 *Reg;
+ UINT32 RegSize;
+ VIRTIO_TRANSPORT_DEVICE_PATH *DevicePath;
+ EFI_HANDLE Handle;
+ UINT64 RegBase;
+
+ Status = gBS->LocateProtocol (&gFdtClientProtocolGuid, NULL,
+ (VOID **)&FdtClient);
+ ASSERT_EFI_ERROR (Status);
+
+ for (FindNodeStatus = FdtClient->FindCompatibleNode (FdtClient,
+ "virtio,mmio", &Node);
+ !EFI_ERROR (FindNodeStatus);
+ FindNodeStatus = FdtClient->FindNextCompatibleNode (FdtClient,
+ "virtio,mmio", Node, &Node)) {
+
+ Status = FdtClient->GetNodeProperty (FdtClient, Node, "reg",
+ (CONST VOID **)&Reg, &RegSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "%a: GetNodeProperty () failed (Status == %r)\n",
+ __FUNCTION__, Status));
+ continue;
+ }
+
+ ASSERT (RegSize == 16);
+
+ //
+ // Create a unique device path for this transport on the fly
+ //
+ RegBase = SwapBytes64 (*Reg);
+ DevicePath = (VIRTIO_TRANSPORT_DEVICE_PATH *)CreateDeviceNode (
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ sizeof (VIRTIO_TRANSPORT_DEVICE_PATH));
+ if (DevicePath == NULL) {
+ DEBUG ((EFI_D_ERROR, "%a: Out of memory\n", __FUNCTION__));
+ continue;
+ }
+
+ CopyGuid (&DevicePath->Vendor.Guid, &gVirtioMmioTransportGuid);
+ DevicePath->PhysBase = RegBase;
+ SetDevicePathNodeLength (&DevicePath->Vendor,
+ sizeof (*DevicePath) - sizeof (DevicePath->End));
+ SetDevicePathEndNode (&DevicePath->End);
+
+ Handle = NULL;
+ Status = gBS->InstallProtocolInterface (&Handle,
+ &gEfiDevicePathProtocolGuid, EFI_NATIVE_INTERFACE,
+ DevicePath);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "%a: Failed to install the EFI_DEVICE_PATH "
+ "protocol on a new handle (Status == %r)\n",
+ __FUNCTION__, Status));
+ FreePool (DevicePath);
+ continue;
+ }
+
+ Status = VirtioMmioInstallDevice (RegBase, Handle);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "%a: Failed to install VirtIO transport @ 0x%Lx "
+ "on handle %p (Status == %r)\n", __FUNCTION__, RegBase,
+ Handle, Status));
+
+ Status = gBS->UninstallProtocolInterface (Handle,
+ &gEfiDevicePathProtocolGuid, DevicePath);
+ ASSERT_EFI_ERROR (Status);
+ FreePool (DevicePath);
+ continue;
+ }
+ }
+
+ if (EFI_ERROR (FindNodeStatus) && FindNodeStatus != EFI_NOT_FOUND) {
+ DEBUG ((EFI_D_ERROR, "%a: Error occurred while iterating DT nodes "
+ "(FindNodeStatus == %r)\n", __FUNCTION__, FindNodeStatus));
+ }
+
+ return EFI_SUCCESS;
+}