]> git.proxmox.com Git - mirror_edk2.git/blob - ArmVirtPkg/VirtFdtDxe/VirtFdtDxe.c
ArmVirtPkg/VirtFdtDxe: drop detection of PSCI method
[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 PropertyTypeRtc,
46 PropertyTypeVirtio,
47 PropertyTypeUart,
48 PropertyTypeTimer,
49 PropertyTypeFwCfg,
50 PropertyTypePciHost,
51 PropertyTypeXen,
52 } PROPERTY_TYPE;
53
54 typedef struct {
55 PROPERTY_TYPE Type;
56 CHAR8 Compatible[32];
57 } PROPERTY;
58
59 STATIC CONST PROPERTY CompatibleProperties[] = {
60 { PropertyTypeRtc, "arm,pl031" },
61 { PropertyTypeVirtio, "virtio,mmio" },
62 { PropertyTypeUart, "arm,pl011" },
63 { PropertyTypeTimer, "arm,armv7-timer" },
64 { PropertyTypeTimer, "arm,armv8-timer" },
65 { PropertyTypeFwCfg, "qemu,fw-cfg-mmio" },
66 { PropertyTypePciHost, "pci-host-ecam-generic" },
67 { PropertyTypeXen, "xen,xen" },
68 { PropertyTypeUnknown, "" }
69 };
70
71 typedef struct {
72 UINT32 Type;
73 UINT32 Number;
74 UINT32 Flags;
75 } INTERRUPT_PROPERTY;
76
77 STATIC
78 PROPERTY_TYPE
79 GetTypeFromNode (
80 IN CONST CHAR8 *NodeType,
81 IN UINTN Size
82 )
83 {
84 CONST CHAR8 *Compatible;
85 CONST PROPERTY *CompatibleProperty;
86
87 //
88 // A 'compatible' node may contain a sequence of NULL terminated
89 // compatible strings so check each one
90 //
91 for (Compatible = NodeType; Compatible < NodeType + Size && *Compatible;
92 Compatible += 1 + AsciiStrLen (Compatible)) {
93 for (CompatibleProperty = CompatibleProperties; CompatibleProperty->Compatible[0]; CompatibleProperty++) {
94 if (AsciiStrCmp (CompatibleProperty->Compatible, Compatible) == 0) {
95 return CompatibleProperty->Type;
96 }
97 }
98 }
99 return PropertyTypeUnknown;
100 }
101
102 //
103 // We expect the "ranges" property of "pci-host-ecam-generic" to consist of
104 // records like this.
105 //
106 #pragma pack (1)
107 typedef struct {
108 UINT32 Type;
109 UINT64 ChildBase;
110 UINT64 CpuBase;
111 UINT64 Size;
112 } DTB_PCI_HOST_RANGE_RECORD;
113 #pragma pack ()
114
115 #define DTB_PCI_HOST_RANGE_RELOCATABLE BIT31
116 #define DTB_PCI_HOST_RANGE_PREFETCHABLE BIT30
117 #define DTB_PCI_HOST_RANGE_ALIASED BIT29
118 #define DTB_PCI_HOST_RANGE_MMIO32 BIT25
119 #define DTB_PCI_HOST_RANGE_MMIO64 (BIT25 | BIT24)
120 #define DTB_PCI_HOST_RANGE_IO BIT24
121 #define DTB_PCI_HOST_RANGE_TYPEMASK (BIT31 | BIT30 | BIT29 | BIT25 | BIT24)
122
123 /**
124 Process the device tree node describing the generic PCI host controller.
125
126 param[in] DeviceTreeBase Pointer to the device tree.
127
128 param[in] Node Offset of the device tree node whose "compatible"
129 property is "pci-host-ecam-generic".
130
131 param[in] RegProp Pointer to the "reg" property of Node. The caller
132 is responsible for ensuring that the size of the
133 property is 4 UINT32 cells.
134
135 @retval EFI_SUCCESS Parsing successful, properties parsed from Node
136 have been stored in dynamic PCDs.
137
138 @retval EFI_PROTOCOL_ERROR Parsing failed. PCDs are left unchanged.
139 **/
140 STATIC
141 EFI_STATUS
142 EFIAPI
143 ProcessPciHost (
144 IN CONST VOID *DeviceTreeBase,
145 IN INT32 Node,
146 IN CONST VOID *RegProp
147 )
148 {
149 UINT64 ConfigBase, ConfigSize;
150 CONST VOID *Prop;
151 INT32 Len;
152 UINT32 BusMin, BusMax;
153 UINT32 RecordIdx;
154 UINT64 IoBase, IoSize, IoTranslation;
155 UINT64 MmioBase, MmioSize, MmioTranslation;
156
157 //
158 // Fetch the ECAM window.
159 //
160 ConfigBase = fdt64_to_cpu (((CONST UINT64 *)RegProp)[0]);
161 ConfigSize = fdt64_to_cpu (((CONST UINT64 *)RegProp)[1]);
162
163 //
164 // Fetch the bus range (note: inclusive).
165 //
166 Prop = fdt_getprop (DeviceTreeBase, Node, "bus-range", &Len);
167 if (Prop == NULL || Len != 2 * sizeof(UINT32)) {
168 DEBUG ((EFI_D_ERROR, "%a: 'bus-range' not found or invalid\n",
169 __FUNCTION__));
170 return EFI_PROTOCOL_ERROR;
171 }
172 BusMin = fdt32_to_cpu (((CONST UINT32 *)Prop)[0]);
173 BusMax = fdt32_to_cpu (((CONST UINT32 *)Prop)[1]);
174
175 //
176 // Sanity check: the config space must accommodate all 4K register bytes of
177 // all 8 functions of all 32 devices of all buses.
178 //
179 if (BusMax < BusMin || BusMax - BusMin == MAX_UINT32 ||
180 DivU64x32 (ConfigSize, SIZE_4KB * 8 * 32) < BusMax - BusMin + 1) {
181 DEBUG ((EFI_D_ERROR, "%a: invalid 'bus-range' and/or 'reg'\n",
182 __FUNCTION__));
183 return EFI_PROTOCOL_ERROR;
184 }
185
186 //
187 // Iterate over "ranges".
188 //
189 Prop = fdt_getprop (DeviceTreeBase, Node, "ranges", &Len);
190 if (Prop == NULL || Len == 0 ||
191 Len % sizeof (DTB_PCI_HOST_RANGE_RECORD) != 0) {
192 DEBUG ((EFI_D_ERROR, "%a: 'ranges' not found or invalid\n", __FUNCTION__));
193 return EFI_PROTOCOL_ERROR;
194 }
195
196 //
197 // IoBase, IoTranslation, MmioBase and MmioTranslation are initialized only
198 // in order to suppress '-Werror=maybe-uninitialized' warnings *incorrectly*
199 // emitted by some gcc versions.
200 //
201 IoBase = 0;
202 IoTranslation = 0;
203 MmioBase = 0;
204 MmioTranslation = 0;
205
206 //
207 // IoSize and MmioSize are initialized to zero because the logic below
208 // requires it.
209 //
210 IoSize = 0;
211 MmioSize = 0;
212 for (RecordIdx = 0; RecordIdx < Len / sizeof (DTB_PCI_HOST_RANGE_RECORD);
213 ++RecordIdx) {
214 CONST DTB_PCI_HOST_RANGE_RECORD *Record;
215
216 Record = (CONST DTB_PCI_HOST_RANGE_RECORD *)Prop + RecordIdx;
217 switch (fdt32_to_cpu (Record->Type) & DTB_PCI_HOST_RANGE_TYPEMASK) {
218 case DTB_PCI_HOST_RANGE_IO:
219 IoBase = fdt64_to_cpu (Record->ChildBase);
220 IoSize = fdt64_to_cpu (Record->Size);
221 IoTranslation = fdt64_to_cpu (Record->CpuBase) - IoBase;
222 break;
223
224 case DTB_PCI_HOST_RANGE_MMIO32:
225 MmioBase = fdt64_to_cpu (Record->ChildBase);
226 MmioSize = fdt64_to_cpu (Record->Size);
227 MmioTranslation = fdt64_to_cpu (Record->CpuBase) - MmioBase;
228
229 if (MmioBase > MAX_UINT32 || MmioSize > MAX_UINT32 ||
230 MmioBase + MmioSize > SIZE_4GB) {
231 DEBUG ((EFI_D_ERROR, "%a: MMIO32 space invalid\n", __FUNCTION__));
232 return EFI_PROTOCOL_ERROR;
233 }
234
235 if (MmioTranslation != 0) {
236 DEBUG ((EFI_D_ERROR, "%a: unsupported nonzero MMIO32 translation "
237 "0x%Lx\n", __FUNCTION__, MmioTranslation));
238 return EFI_UNSUPPORTED;
239 }
240
241 break;
242 }
243 }
244 if (IoSize == 0 || MmioSize == 0) {
245 DEBUG ((EFI_D_ERROR, "%a: %a space empty\n", __FUNCTION__,
246 (IoSize == 0) ? "IO" : "MMIO32"));
247 return EFI_PROTOCOL_ERROR;
248 }
249
250 PcdSet64 (PcdPciExpressBaseAddress, ConfigBase);
251
252 PcdSet32 (PcdPciBusMin, BusMin);
253 PcdSet32 (PcdPciBusMax, BusMax);
254
255 PcdSet64 (PcdPciIoBase, IoBase);
256 PcdSet64 (PcdPciIoSize, IoSize);
257 PcdSet64 (PcdPciIoTranslation, IoTranslation);
258
259 PcdSet32 (PcdPciMmio32Base, (UINT32)MmioBase);
260 PcdSet32 (PcdPciMmio32Size, (UINT32)MmioSize);
261
262 PcdSetBool (PcdPciDisableBusEnumeration, FALSE);
263
264 DEBUG ((EFI_D_INFO, "%a: Config[0x%Lx+0x%Lx) Bus[0x%x..0x%x] "
265 "Io[0x%Lx+0x%Lx)@0x%Lx Mem[0x%Lx+0x%Lx)@0x%Lx\n", __FUNCTION__, ConfigBase,
266 ConfigSize, BusMin, BusMax, IoBase, IoSize, IoTranslation, MmioBase,
267 MmioSize, MmioTranslation));
268 return EFI_SUCCESS;
269 }
270
271
272 EFI_STATUS
273 EFIAPI
274 InitializeVirtFdtDxe (
275 IN EFI_HANDLE ImageHandle,
276 IN EFI_SYSTEM_TABLE *SystemTable
277 )
278 {
279 VOID *Hob;
280 VOID *DeviceTreeBase;
281 INT32 Node, Prev;
282 INT32 RtcNode;
283 EFI_STATUS Status;
284 CONST CHAR8 *Type;
285 INT32 Len;
286 PROPERTY_TYPE PropType;
287 CONST VOID *RegProp;
288 VIRTIO_TRANSPORT_DEVICE_PATH *DevicePath;
289 EFI_HANDLE Handle;
290 UINT64 RegBase;
291 CONST INTERRUPT_PROPERTY *InterruptProp;
292 INT32 SecIntrNum, IntrNum, VirtIntrNum, HypIntrNum;
293 UINT64 FwCfgSelectorAddress;
294 UINT64 FwCfgSelectorSize;
295 UINT64 FwCfgDataAddress;
296 UINT64 FwCfgDataSize;
297 UINT64 FwCfgDmaAddress;
298 UINT64 FwCfgDmaSize;
299 BOOLEAN HavePci;
300
301 Hob = GetFirstGuidHob(&gFdtHobGuid);
302 if (Hob == NULL || GET_GUID_HOB_DATA_SIZE (Hob) != sizeof (UINT64)) {
303 return EFI_NOT_FOUND;
304 }
305 DeviceTreeBase = (VOID *)(UINTN)*(UINT64 *)GET_GUID_HOB_DATA (Hob);
306
307 if (fdt_check_header (DeviceTreeBase) != 0) {
308 DEBUG ((EFI_D_ERROR, "%a: No DTB found @ 0x%p\n", __FUNCTION__, DeviceTreeBase));
309 return EFI_NOT_FOUND;
310 }
311
312 DEBUG ((EFI_D_INFO, "%a: DTB @ 0x%p\n", __FUNCTION__, DeviceTreeBase));
313
314 RtcNode = -1;
315 HavePci = FALSE;
316 //
317 // Now enumerate the nodes and install peripherals that we are interested in,
318 // i.e., GIC, RTC and virtio MMIO nodes
319 //
320 for (Prev = 0;; Prev = Node) {
321 Node = fdt_next_node (DeviceTreeBase, Prev, NULL);
322 if (Node < 0) {
323 break;
324 }
325
326 Type = fdt_getprop (DeviceTreeBase, Node, "compatible", &Len);
327 if (Type == NULL) {
328 continue;
329 }
330
331 PropType = GetTypeFromNode (Type, Len);
332 if (PropType == PropertyTypeUnknown) {
333 continue;
334 }
335
336 //
337 // Get the 'reg' property of this node. For now, we will assume
338 // 8 byte quantities for base and size, respectively.
339 // TODO use #cells root properties instead
340 //
341 RegProp = fdt_getprop (DeviceTreeBase, Node, "reg", &Len);
342 ASSERT ((RegProp != NULL) || (PropType == PropertyTypeTimer));
343
344 switch (PropType) {
345 case PropertyTypePciHost:
346 ASSERT (Len == 2 * sizeof (UINT64));
347 Status = ProcessPciHost (DeviceTreeBase, Node, RegProp);
348 ASSERT_EFI_ERROR (Status);
349 HavePci = TRUE;
350 break;
351
352 case PropertyTypeFwCfg:
353 ASSERT (Len == 2 * sizeof (UINT64));
354
355 FwCfgDataAddress = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
356 FwCfgDataSize = 8;
357 FwCfgSelectorAddress = FwCfgDataAddress + FwCfgDataSize;
358 FwCfgSelectorSize = 2;
359
360 //
361 // The following ASSERT()s express
362 //
363 // Address + Size - 1 <= MAX_UINTN
364 //
365 // for both registers, that is, that the last byte in each MMIO range is
366 // expressible as a MAX_UINTN. The form below is mathematically
367 // equivalent, and it also prevents any unsigned overflow before the
368 // comparison.
369 //
370 ASSERT (FwCfgSelectorAddress <= MAX_UINTN - FwCfgSelectorSize + 1);
371 ASSERT (FwCfgDataAddress <= MAX_UINTN - FwCfgDataSize + 1);
372
373 PcdSet64 (PcdFwCfgSelectorAddress, FwCfgSelectorAddress);
374 PcdSet64 (PcdFwCfgDataAddress, FwCfgDataAddress);
375
376 DEBUG ((EFI_D_INFO, "Found FwCfg @ 0x%Lx/0x%Lx\n", FwCfgSelectorAddress,
377 FwCfgDataAddress));
378
379 if (fdt64_to_cpu (((UINT64 *)RegProp)[1]) >= 0x18) {
380 FwCfgDmaAddress = FwCfgDataAddress + 0x10;
381 FwCfgDmaSize = 0x08;
382
383 //
384 // See explanation above.
385 //
386 ASSERT (FwCfgDmaAddress <= MAX_UINTN - FwCfgDmaSize + 1);
387
388 PcdSet64 (PcdFwCfgDmaAddress, FwCfgDmaAddress);
389 DEBUG ((EFI_D_INFO, "Found FwCfg DMA @ 0x%Lx\n", FwCfgDmaAddress));
390 }
391 break;
392
393 case PropertyTypeVirtio:
394 ASSERT (Len == 16);
395 //
396 // Create a unique device path for this transport on the fly
397 //
398 RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
399 DevicePath = (VIRTIO_TRANSPORT_DEVICE_PATH *)CreateDeviceNode (
400 HARDWARE_DEVICE_PATH,
401 HW_VENDOR_DP,
402 sizeof (VIRTIO_TRANSPORT_DEVICE_PATH));
403 if (DevicePath == NULL) {
404 DEBUG ((EFI_D_ERROR, "%a: Out of memory\n", __FUNCTION__));
405 break;
406 }
407
408 CopyMem (&DevicePath->Vendor.Guid, &gVirtioMmioTransportGuid,
409 sizeof (EFI_GUID));
410 DevicePath->PhysBase = RegBase;
411 SetDevicePathNodeLength (&DevicePath->Vendor,
412 sizeof (*DevicePath) - sizeof (DevicePath->End));
413 SetDevicePathEndNode (&DevicePath->End);
414
415 Handle = NULL;
416 Status = gBS->InstallProtocolInterface (&Handle,
417 &gEfiDevicePathProtocolGuid, EFI_NATIVE_INTERFACE,
418 DevicePath);
419 if (EFI_ERROR (Status)) {
420 DEBUG ((EFI_D_ERROR, "%a: Failed to install the EFI_DEVICE_PATH "
421 "protocol on a new handle (Status == %r)\n",
422 __FUNCTION__, Status));
423 FreePool (DevicePath);
424 break;
425 }
426
427 Status = VirtioMmioInstallDevice (RegBase, Handle);
428 if (EFI_ERROR (Status)) {
429 DEBUG ((EFI_D_ERROR, "%a: Failed to install VirtIO transport @ 0x%Lx "
430 "on handle %p (Status == %r)\n", __FUNCTION__, RegBase,
431 Handle, Status));
432
433 Status = gBS->UninstallProtocolInterface (Handle,
434 &gEfiDevicePathProtocolGuid, DevicePath);
435 ASSERT_EFI_ERROR (Status);
436 FreePool (DevicePath);
437 }
438 break;
439
440 case PropertyTypeRtc:
441 ASSERT (Len == 16);
442
443 RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
444 ASSERT (RegBase < MAX_UINT32);
445
446 PcdSet32 (PcdPL031RtcBase, (UINT32)RegBase);
447
448 DEBUG ((EFI_D_INFO, "Found PL031 RTC @ 0x%Lx\n", RegBase));
449 RtcNode = Node;
450 break;
451
452 case PropertyTypeTimer:
453 //
454 // - interrupts : Interrupt list for secure, non-secure, virtual and
455 // hypervisor timers, in that order.
456 //
457 InterruptProp = fdt_getprop (DeviceTreeBase, Node, "interrupts", &Len);
458 ASSERT (Len == 36 || Len == 48);
459
460 SecIntrNum = fdt32_to_cpu (InterruptProp[0].Number)
461 + (InterruptProp[0].Type ? 16 : 0);
462 IntrNum = fdt32_to_cpu (InterruptProp[1].Number)
463 + (InterruptProp[1].Type ? 16 : 0);
464 VirtIntrNum = fdt32_to_cpu (InterruptProp[2].Number)
465 + (InterruptProp[2].Type ? 16 : 0);
466 HypIntrNum = Len < 48 ? 0 : fdt32_to_cpu (InterruptProp[3].Number)
467 + (InterruptProp[3].Type ? 16 : 0);
468
469 DEBUG ((EFI_D_INFO, "Found Timer interrupts %d, %d, %d, %d\n",
470 SecIntrNum, IntrNum, VirtIntrNum, HypIntrNum));
471
472 PcdSet32 (PcdArmArchTimerSecIntrNum, SecIntrNum);
473 PcdSet32 (PcdArmArchTimerIntrNum, IntrNum);
474 PcdSet32 (PcdArmArchTimerVirtIntrNum, VirtIntrNum);
475 PcdSet32 (PcdArmArchTimerHypIntrNum, HypIntrNum);
476 break;
477
478 case PropertyTypeXen:
479 ASSERT (Len == 16);
480
481 //
482 // Retrieve the reg base from this node and wire it up to the
483 // MMIO flavor of the XenBus root device I/O protocol
484 //
485 RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
486 Handle = NULL;
487 Status = XenIoMmioInstall (&Handle, RegBase);
488 if (EFI_ERROR (Status)) {
489 DEBUG ((EFI_D_ERROR, "%a: XenIoMmioInstall () failed on a new handle "
490 "(Status == %r)\n", __FUNCTION__, Status));
491 break;
492 }
493
494 DEBUG ((EFI_D_INFO, "Found Xen node with Grant table @ 0x%Lx\n", RegBase));
495
496 break;
497
498 default:
499 break;
500 }
501 }
502
503 if (!FeaturePcdGet (PcdPureAcpiBoot)) {
504 //
505 // Only install the FDT as a configuration table if we want to leave it up
506 // to the OS to decide whether it prefers ACPI over DT.
507 //
508 Status = gBS->InstallConfigurationTable (&gFdtTableGuid, DeviceTreeBase);
509 ASSERT_EFI_ERROR (Status);
510
511 //
512 // UEFI takes ownership of the RTC hardware, and exposes its functionality
513 // through the UEFI Runtime Services GetTime, SetTime, etc. This means we
514 // need to disable it in the device tree to prevent the OS from attaching its
515 // device driver as well.
516 //
517 if ((RtcNode != -1) &&
518 fdt_setprop_string (DeviceTreeBase, RtcNode, "status",
519 "disabled") != 0) {
520 DEBUG ((EFI_D_WARN, "Failed to set PL031 status to 'disabled'\n"));
521 }
522
523 if (HavePci) {
524 //
525 // Set the /chosen/linux,pci-probe-only property to 1, so that the PCI
526 // setup we will perform in the firmware is honored by the Linux OS,
527 // rather than torn down and done from scratch. This is generally a more
528 // sensible approach, and aligns with what ACPI based OSes do in general.
529 //
530 // In case we are exposing an emulated VGA PCI device to the guest, which
531 // may subsequently get exposed via the Graphics Output protocol and
532 // driven as an efifb by Linux, we need this setting to prevent the
533 // framebuffer from becoming unresponsive.
534 //
535 Node = fdt_path_offset (DeviceTreeBase, "/chosen");
536 if (Node < 0) {
537 Node = fdt_add_subnode (DeviceTreeBase, 0, "/chosen");
538 }
539 if (Node < 0 ||
540 fdt_setprop_u32 (DeviceTreeBase, Node, "linux,pci-probe-only", 1) < 0) {
541 DEBUG ((EFI_D_WARN, "Failed to set /chosen/linux,pci-probe-only property\n"));
542 }
543 }
544 }
545 return EFI_SUCCESS;
546 }