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