• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
GetTypeFromNode(IN CONST CHAR8 * NodeType,IN UINTN Size)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
ProcessPciHost(IN CONST VOID * DeviceTreeBase,IN INT32 Node,IN CONST VOID * RegProp)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
InitializeVirtFdtDxe(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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 
308   Hob = GetFirstGuidHob(&gFdtHobGuid);
309   if (Hob == NULL || GET_GUID_HOB_DATA_SIZE (Hob) != sizeof (UINT64)) {
310     return EFI_NOT_FOUND;
311   }
312   DeviceTreeBase = (VOID *)(UINTN)*(UINT64 *)GET_GUID_HOB_DATA (Hob);
313 
314   if (fdt_check_header (DeviceTreeBase) != 0) {
315     DEBUG ((EFI_D_ERROR, "%a: No DTB found @ 0x%p\n", __FUNCTION__, DeviceTreeBase));
316     return EFI_NOT_FOUND;
317   }
318 
319   Status = gBS->InstallConfigurationTable (&gFdtTableGuid, DeviceTreeBase);
320   ASSERT_EFI_ERROR (Status);
321 
322   DEBUG ((EFI_D_INFO, "%a: DTB @ 0x%p\n", __FUNCTION__, DeviceTreeBase));
323 
324   RtcNode = -1;
325   //
326   // Now enumerate the nodes and install peripherals that we are interested in,
327   // i.e., GIC, RTC and virtio MMIO nodes
328   //
329   for (Prev = 0;; Prev = Node) {
330     Node = fdt_next_node (DeviceTreeBase, Prev, NULL);
331     if (Node < 0) {
332       break;
333     }
334 
335     Type = fdt_getprop (DeviceTreeBase, Node, "compatible", &Len);
336     if (Type == NULL) {
337       continue;
338     }
339 
340     PropType = GetTypeFromNode (Type, Len);
341     if (PropType == PropertyTypeUnknown) {
342       continue;
343     }
344 
345     //
346     // Get the 'reg' property of this node. For now, we will assume
347     // 8 byte quantities for base and size, respectively.
348     // TODO use #cells root properties instead
349     //
350     RegProp = fdt_getprop (DeviceTreeBase, Node, "reg", &Len);
351     ASSERT ((RegProp != NULL) || (PropType == PropertyTypeTimer) ||
352       (PropType == PropertyTypePsci));
353 
354     switch (PropType) {
355     case PropertyTypePciHost:
356       ASSERT (Len == 2 * sizeof (UINT64));
357       Status = ProcessPciHost (DeviceTreeBase, Node, RegProp);
358       ASSERT_EFI_ERROR (Status);
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   //
572   // UEFI takes ownership of the RTC hardware, and exposes its functionality
573   // through the UEFI Runtime Services GetTime, SetTime, etc. This means we
574   // need to disable it in the device tree to prevent the OS from attaching its
575   // device driver as well.
576   //
577   if ((RtcNode != -1) &&
578       fdt_setprop_string (DeviceTreeBase, RtcNode, "status",
579         "disabled") != 0) {
580     DEBUG ((EFI_D_WARN, "Failed to set PL031 status to 'disabled'\n"));
581   }
582   return EFI_SUCCESS;
583 }
584