]> git.proxmox.com Git - mirror_edk2.git/blob - ArmVirtPkg/VirtFdtDxe/VirtFdtDxe.c
8fe1277b6b498884552184aba9f140bd512bc16c
[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/Fdt.h>
32 #include <Guid/VirtioMmioTransport.h>
33 #include <Guid/FdtHob.h>
34
35 #pragma pack (1)
36 typedef struct {
37 VENDOR_DEVICE_PATH Vendor;
38 UINT64 PhysBase;
39 EFI_DEVICE_PATH_PROTOCOL End;
40 } VIRTIO_TRANSPORT_DEVICE_PATH;
41 #pragma pack ()
42
43 typedef enum {
44 PropertyTypeUnknown,
45 PropertyTypeVirtio,
46 PropertyTypeXen,
47 } PROPERTY_TYPE;
48
49 typedef struct {
50 PROPERTY_TYPE Type;
51 CHAR8 Compatible[32];
52 } PROPERTY;
53
54 STATIC CONST PROPERTY CompatibleProperties[] = {
55 { PropertyTypeVirtio, "virtio,mmio" },
56 { PropertyTypeXen, "xen,xen" },
57 { PropertyTypeUnknown, "" }
58 };
59
60 STATIC
61 PROPERTY_TYPE
62 GetTypeFromNode (
63 IN CONST CHAR8 *NodeType,
64 IN UINTN Size
65 )
66 {
67 CONST CHAR8 *Compatible;
68 CONST PROPERTY *CompatibleProperty;
69
70 //
71 // A 'compatible' node may contain a sequence of NULL terminated
72 // compatible strings so check each one
73 //
74 for (Compatible = NodeType; Compatible < NodeType + Size && *Compatible;
75 Compatible += 1 + AsciiStrLen (Compatible)) {
76 for (CompatibleProperty = CompatibleProperties; CompatibleProperty->Compatible[0]; CompatibleProperty++) {
77 if (AsciiStrCmp (CompatibleProperty->Compatible, Compatible) == 0) {
78 return CompatibleProperty->Type;
79 }
80 }
81 }
82 return PropertyTypeUnknown;
83 }
84
85 EFI_STATUS
86 EFIAPI
87 InitializeVirtFdtDxe (
88 IN EFI_HANDLE ImageHandle,
89 IN EFI_SYSTEM_TABLE *SystemTable
90 )
91 {
92 VOID *Hob;
93 VOID *DeviceTreeBase;
94 INT32 Node, Prev;
95 EFI_STATUS Status;
96 CONST CHAR8 *Type;
97 INT32 Len;
98 PROPERTY_TYPE PropType;
99 CONST VOID *RegProp;
100 VIRTIO_TRANSPORT_DEVICE_PATH *DevicePath;
101 EFI_HANDLE Handle;
102 UINT64 RegBase;
103
104 Hob = GetFirstGuidHob(&gFdtHobGuid);
105 if (Hob == NULL || GET_GUID_HOB_DATA_SIZE (Hob) != sizeof (UINT64)) {
106 return EFI_NOT_FOUND;
107 }
108 DeviceTreeBase = (VOID *)(UINTN)*(UINT64 *)GET_GUID_HOB_DATA (Hob);
109
110 if (fdt_check_header (DeviceTreeBase) != 0) {
111 DEBUG ((EFI_D_ERROR, "%a: No DTB found @ 0x%p\n", __FUNCTION__, DeviceTreeBase));
112 return EFI_NOT_FOUND;
113 }
114
115 DEBUG ((EFI_D_INFO, "%a: DTB @ 0x%p\n", __FUNCTION__, DeviceTreeBase));
116
117 //
118 // Now enumerate the nodes and install peripherals that we are interested in,
119 // i.e., GIC, RTC and virtio MMIO nodes
120 //
121 for (Prev = 0;; Prev = Node) {
122 Node = fdt_next_node (DeviceTreeBase, Prev, NULL);
123 if (Node < 0) {
124 break;
125 }
126
127 Type = fdt_getprop (DeviceTreeBase, Node, "compatible", &Len);
128 if (Type == NULL) {
129 continue;
130 }
131
132 PropType = GetTypeFromNode (Type, Len);
133 if (PropType == PropertyTypeUnknown) {
134 continue;
135 }
136
137 //
138 // Get the 'reg' property of this node. For now, we will assume
139 // 8 byte quantities for base and size, respectively.
140 // TODO use #cells root properties instead
141 //
142 RegProp = fdt_getprop (DeviceTreeBase, Node, "reg", &Len);
143 ASSERT (RegProp != NULL);
144
145 switch (PropType) {
146 case PropertyTypeVirtio:
147 ASSERT (Len == 16);
148 //
149 // Create a unique device path for this transport on the fly
150 //
151 RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
152 DevicePath = (VIRTIO_TRANSPORT_DEVICE_PATH *)CreateDeviceNode (
153 HARDWARE_DEVICE_PATH,
154 HW_VENDOR_DP,
155 sizeof (VIRTIO_TRANSPORT_DEVICE_PATH));
156 if (DevicePath == NULL) {
157 DEBUG ((EFI_D_ERROR, "%a: Out of memory\n", __FUNCTION__));
158 break;
159 }
160
161 CopyMem (&DevicePath->Vendor.Guid, &gVirtioMmioTransportGuid,
162 sizeof (EFI_GUID));
163 DevicePath->PhysBase = RegBase;
164 SetDevicePathNodeLength (&DevicePath->Vendor,
165 sizeof (*DevicePath) - sizeof (DevicePath->End));
166 SetDevicePathEndNode (&DevicePath->End);
167
168 Handle = NULL;
169 Status = gBS->InstallProtocolInterface (&Handle,
170 &gEfiDevicePathProtocolGuid, EFI_NATIVE_INTERFACE,
171 DevicePath);
172 if (EFI_ERROR (Status)) {
173 DEBUG ((EFI_D_ERROR, "%a: Failed to install the EFI_DEVICE_PATH "
174 "protocol on a new handle (Status == %r)\n",
175 __FUNCTION__, Status));
176 FreePool (DevicePath);
177 break;
178 }
179
180 Status = VirtioMmioInstallDevice (RegBase, Handle);
181 if (EFI_ERROR (Status)) {
182 DEBUG ((EFI_D_ERROR, "%a: Failed to install VirtIO transport @ 0x%Lx "
183 "on handle %p (Status == %r)\n", __FUNCTION__, RegBase,
184 Handle, Status));
185
186 Status = gBS->UninstallProtocolInterface (Handle,
187 &gEfiDevicePathProtocolGuid, DevicePath);
188 ASSERT_EFI_ERROR (Status);
189 FreePool (DevicePath);
190 }
191 break;
192
193 case PropertyTypeXen:
194 ASSERT (Len == 16);
195
196 //
197 // Retrieve the reg base from this node and wire it up to the
198 // MMIO flavor of the XenBus root device I/O protocol
199 //
200 RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
201 Handle = NULL;
202 Status = XenIoMmioInstall (&Handle, RegBase);
203 if (EFI_ERROR (Status)) {
204 DEBUG ((EFI_D_ERROR, "%a: XenIoMmioInstall () failed on a new handle "
205 "(Status == %r)\n", __FUNCTION__, Status));
206 break;
207 }
208
209 DEBUG ((EFI_D_INFO, "Found Xen node with Grant table @ 0x%Lx\n", RegBase));
210
211 break;
212
213 default:
214 break;
215 }
216 }
217
218 if (!FeaturePcdGet (PcdPureAcpiBoot)) {
219 //
220 // Only install the FDT as a configuration table if we want to leave it up
221 // to the OS to decide whether it prefers ACPI over DT.
222 //
223 Status = gBS->InstallConfigurationTable (&gFdtTableGuid, DeviceTreeBase);
224 ASSERT_EFI_ERROR (Status);
225 }
226
227 return EFI_SUCCESS;
228 }