]> git.proxmox.com Git - mirror_edk2.git/blob - ArmVirtPkg/VirtFdtDxe/VirtFdtDxe.c
ArmVirtPkg/ArmVirtXen: move from VirtFdtDxe to new XenioFdtDxe driver
[mirror_edk2.git] / ArmVirtPkg / VirtFdtDxe / VirtFdtDxe.c
1 /** @file
2 * Device tree enumeration DXE driver for ARM Virtual Machines
3 *
4 * Copyright (c) 2014, Linaro Ltd. All rights reserved.<BR>
5 *
6 * This program and the accompanying materials are
7 * licensed and made available under the terms and conditions of the BSD License
8 * which accompanies this distribution. The full text of the license may be found at
9 * http://opensource.org/licenses/bsd-license.php
10 *
11 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 *
14 **/
15
16 #include <Library/BaseLib.h>
17 #include <Library/DebugLib.h>
18 #include <Library/UefiLib.h>
19 #include <Library/BaseMemoryLib.h>
20 #include <Library/UefiDriverEntryPoint.h>
21 #include <Library/MemoryAllocationLib.h>
22 #include <Library/UefiBootServicesTableLib.h>
23 #include <Library/VirtioMmioDeviceLib.h>
24 #include <Library/DevicePathLib.h>
25 #include <Library/PcdLib.h>
26 #include <Library/DxeServicesLib.h>
27 #include <Library/HobLib.h>
28 #include <libfdt.h>
29 #include <Library/XenIoMmioLib.h>
30
31 #include <Guid/VirtioMmioTransport.h>
32 #include <Guid/FdtHob.h>
33
34 #pragma pack (1)
35 typedef struct {
36 VENDOR_DEVICE_PATH Vendor;
37 UINT64 PhysBase;
38 EFI_DEVICE_PATH_PROTOCOL End;
39 } VIRTIO_TRANSPORT_DEVICE_PATH;
40 #pragma pack ()
41
42 typedef enum {
43 PropertyTypeUnknown,
44 PropertyTypeVirtio,
45 PropertyTypeXen,
46 } PROPERTY_TYPE;
47
48 typedef struct {
49 PROPERTY_TYPE Type;
50 CHAR8 Compatible[32];
51 } PROPERTY;
52
53 STATIC CONST PROPERTY CompatibleProperties[] = {
54 { PropertyTypeVirtio, "virtio,mmio" },
55 { PropertyTypeXen, "xen,xen" },
56 { PropertyTypeUnknown, "" }
57 };
58
59 STATIC
60 PROPERTY_TYPE
61 GetTypeFromNode (
62 IN CONST CHAR8 *NodeType,
63 IN UINTN Size
64 )
65 {
66 CONST CHAR8 *Compatible;
67 CONST PROPERTY *CompatibleProperty;
68
69 //
70 // A 'compatible' node may contain a sequence of NULL terminated
71 // compatible strings so check each one
72 //
73 for (Compatible = NodeType; Compatible < NodeType + Size && *Compatible;
74 Compatible += 1 + AsciiStrLen (Compatible)) {
75 for (CompatibleProperty = CompatibleProperties; CompatibleProperty->Compatible[0]; CompatibleProperty++) {
76 if (AsciiStrCmp (CompatibleProperty->Compatible, Compatible) == 0) {
77 return CompatibleProperty->Type;
78 }
79 }
80 }
81 return PropertyTypeUnknown;
82 }
83
84 EFI_STATUS
85 EFIAPI
86 InitializeVirtFdtDxe (
87 IN EFI_HANDLE ImageHandle,
88 IN EFI_SYSTEM_TABLE *SystemTable
89 )
90 {
91 VOID *Hob;
92 VOID *DeviceTreeBase;
93 INT32 Node, Prev;
94 EFI_STATUS Status;
95 CONST CHAR8 *Type;
96 INT32 Len;
97 PROPERTY_TYPE PropType;
98 CONST VOID *RegProp;
99 VIRTIO_TRANSPORT_DEVICE_PATH *DevicePath;
100 EFI_HANDLE Handle;
101 UINT64 RegBase;
102
103 Hob = GetFirstGuidHob(&gFdtHobGuid);
104 if (Hob == NULL || GET_GUID_HOB_DATA_SIZE (Hob) != sizeof (UINT64)) {
105 return EFI_NOT_FOUND;
106 }
107 DeviceTreeBase = (VOID *)(UINTN)*(UINT64 *)GET_GUID_HOB_DATA (Hob);
108
109 if (fdt_check_header (DeviceTreeBase) != 0) {
110 DEBUG ((EFI_D_ERROR, "%a: No DTB found @ 0x%p\n", __FUNCTION__, DeviceTreeBase));
111 return EFI_NOT_FOUND;
112 }
113
114 DEBUG ((EFI_D_INFO, "%a: DTB @ 0x%p\n", __FUNCTION__, DeviceTreeBase));
115
116 //
117 // Now enumerate the nodes and install peripherals that we are interested in,
118 // i.e., GIC, RTC and virtio MMIO nodes
119 //
120 for (Prev = 0;; Prev = Node) {
121 Node = fdt_next_node (DeviceTreeBase, Prev, NULL);
122 if (Node < 0) {
123 break;
124 }
125
126 Type = fdt_getprop (DeviceTreeBase, Node, "compatible", &Len);
127 if (Type == NULL) {
128 continue;
129 }
130
131 PropType = GetTypeFromNode (Type, Len);
132 if (PropType == PropertyTypeUnknown) {
133 continue;
134 }
135
136 //
137 // Get the 'reg' property of this node. For now, we will assume
138 // 8 byte quantities for base and size, respectively.
139 // TODO use #cells root properties instead
140 //
141 RegProp = fdt_getprop (DeviceTreeBase, Node, "reg", &Len);
142 ASSERT (RegProp != NULL);
143
144 switch (PropType) {
145 case PropertyTypeVirtio:
146 ASSERT (Len == 16);
147 //
148 // Create a unique device path for this transport on the fly
149 //
150 RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
151 DevicePath = (VIRTIO_TRANSPORT_DEVICE_PATH *)CreateDeviceNode (
152 HARDWARE_DEVICE_PATH,
153 HW_VENDOR_DP,
154 sizeof (VIRTIO_TRANSPORT_DEVICE_PATH));
155 if (DevicePath == NULL) {
156 DEBUG ((EFI_D_ERROR, "%a: Out of memory\n", __FUNCTION__));
157 break;
158 }
159
160 CopyMem (&DevicePath->Vendor.Guid, &gVirtioMmioTransportGuid,
161 sizeof (EFI_GUID));
162 DevicePath->PhysBase = RegBase;
163 SetDevicePathNodeLength (&DevicePath->Vendor,
164 sizeof (*DevicePath) - sizeof (DevicePath->End));
165 SetDevicePathEndNode (&DevicePath->End);
166
167 Handle = NULL;
168 Status = gBS->InstallProtocolInterface (&Handle,
169 &gEfiDevicePathProtocolGuid, EFI_NATIVE_INTERFACE,
170 DevicePath);
171 if (EFI_ERROR (Status)) {
172 DEBUG ((EFI_D_ERROR, "%a: Failed to install the EFI_DEVICE_PATH "
173 "protocol on a new handle (Status == %r)\n",
174 __FUNCTION__, Status));
175 FreePool (DevicePath);
176 break;
177 }
178
179 Status = VirtioMmioInstallDevice (RegBase, Handle);
180 if (EFI_ERROR (Status)) {
181 DEBUG ((EFI_D_ERROR, "%a: Failed to install VirtIO transport @ 0x%Lx "
182 "on handle %p (Status == %r)\n", __FUNCTION__, RegBase,
183 Handle, Status));
184
185 Status = gBS->UninstallProtocolInterface (Handle,
186 &gEfiDevicePathProtocolGuid, DevicePath);
187 ASSERT_EFI_ERROR (Status);
188 FreePool (DevicePath);
189 }
190 break;
191
192 case PropertyTypeXen:
193 ASSERT (Len == 16);
194
195 //
196 // Retrieve the reg base from this node and wire it up to the
197 // MMIO flavor of the XenBus root device I/O protocol
198 //
199 RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
200 Handle = NULL;
201 Status = XenIoMmioInstall (&Handle, RegBase);
202 if (EFI_ERROR (Status)) {
203 DEBUG ((EFI_D_ERROR, "%a: XenIoMmioInstall () failed on a new handle "
204 "(Status == %r)\n", __FUNCTION__, Status));
205 break;
206 }
207
208 DEBUG ((EFI_D_INFO, "Found Xen node with Grant table @ 0x%Lx\n", RegBase));
209
210 break;
211
212 default:
213 break;
214 }
215 }
216
217 return EFI_SUCCESS;
218 }