]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/ArmVirtualizationPkg/VirtFdtDxe/VirtFdtDxe.c
ArmVirtualizationPkg/VirtFdtDxe: wire up XenBusDxe to "xen,xen" DT node
[mirror_edk2.git] / ArmPlatformPkg / ArmVirtualizationPkg / 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
306 Hob = GetFirstGuidHob(&gFdtHobGuid);
307 if (Hob == NULL || GET_GUID_HOB_DATA_SIZE (Hob) != sizeof (UINT64)) {
308 return EFI_NOT_FOUND;
309 }
310 DeviceTreeBase = (VOID *)(UINTN)*(UINT64 *)GET_GUID_HOB_DATA (Hob);
311
312 if (fdt_check_header (DeviceTreeBase) != 0) {
313 DEBUG ((EFI_D_ERROR, "%a: No DTB found @ 0x%p\n", __FUNCTION__, DeviceTreeBase));
314 return EFI_NOT_FOUND;
315 }
316
317 Status = gBS->InstallConfigurationTable (&gFdtTableGuid, DeviceTreeBase);
318 ASSERT_EFI_ERROR (Status);
319
320 DEBUG ((EFI_D_INFO, "%a: DTB @ 0x%p\n", __FUNCTION__, DeviceTreeBase));
321
322 RtcNode = -1;
323 //
324 // Now enumerate the nodes and install peripherals that we are interested in,
325 // i.e., GIC, RTC and virtio MMIO nodes
326 //
327 for (Prev = 0;; Prev = Node) {
328 Node = fdt_next_node (DeviceTreeBase, Prev, NULL);
329 if (Node < 0) {
330 break;
331 }
332
333 Type = fdt_getprop (DeviceTreeBase, Node, "compatible", &Len);
334 if (Type == NULL) {
335 continue;
336 }
337
338 PropType = GetTypeFromNode (Type, Len);
339 if (PropType == PropertyTypeUnknown) {
340 continue;
341 }
342
343 //
344 // Get the 'reg' property of this node. For now, we will assume
345 // 8 byte quantities for base and size, respectively.
346 // TODO use #cells root properties instead
347 //
348 RegProp = fdt_getprop (DeviceTreeBase, Node, "reg", &Len);
349 ASSERT ((RegProp != NULL) || (PropType == PropertyTypeTimer) ||
350 (PropType == PropertyTypePsci));
351
352 switch (PropType) {
353 case PropertyTypePciHost:
354 ASSERT (Len == 2 * sizeof (UINT64));
355 Status = ProcessPciHost (DeviceTreeBase, Node, RegProp);
356 ASSERT_EFI_ERROR (Status);
357 break;
358
359 case PropertyTypeFwCfg:
360 ASSERT (Len == 2 * sizeof (UINT64));
361
362 FwCfgDataAddress = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
363 FwCfgDataSize = 8;
364 FwCfgSelectorAddress = FwCfgDataAddress + FwCfgDataSize;
365 FwCfgSelectorSize = 2;
366
367 //
368 // The following ASSERT()s express
369 //
370 // Address + Size - 1 <= MAX_UINTN
371 //
372 // for both registers, that is, that the last byte in each MMIO range is
373 // expressible as a MAX_UINTN. The form below is mathematically
374 // equivalent, and it also prevents any unsigned overflow before the
375 // comparison.
376 //
377 ASSERT (FwCfgSelectorAddress <= MAX_UINTN - FwCfgSelectorSize + 1);
378 ASSERT (FwCfgDataAddress <= MAX_UINTN - FwCfgDataSize + 1);
379
380 PcdSet64 (PcdFwCfgSelectorAddress, FwCfgSelectorAddress);
381 PcdSet64 (PcdFwCfgDataAddress, FwCfgDataAddress);
382
383 DEBUG ((EFI_D_INFO, "Found FwCfg @ 0x%Lx/0x%Lx\n", FwCfgSelectorAddress,
384 FwCfgDataAddress));
385 break;
386
387 case PropertyTypeVirtio:
388 ASSERT (Len == 16);
389 //
390 // Create a unique device path for this transport on the fly
391 //
392 RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
393 DevicePath = (VIRTIO_TRANSPORT_DEVICE_PATH *)CreateDeviceNode (
394 HARDWARE_DEVICE_PATH,
395 HW_VENDOR_DP,
396 sizeof (VIRTIO_TRANSPORT_DEVICE_PATH));
397 if (DevicePath == NULL) {
398 DEBUG ((EFI_D_ERROR, "%a: Out of memory\n", __FUNCTION__));
399 break;
400 }
401
402 CopyMem (&DevicePath->Vendor.Guid, &gVirtioMmioTransportGuid,
403 sizeof (EFI_GUID));
404 DevicePath->PhysBase = RegBase;
405 SetDevicePathNodeLength (&DevicePath->Vendor,
406 sizeof (*DevicePath) - sizeof (DevicePath->End));
407 SetDevicePathEndNode (&DevicePath->End);
408
409 Handle = NULL;
410 Status = gBS->InstallProtocolInterface (&Handle,
411 &gEfiDevicePathProtocolGuid, EFI_NATIVE_INTERFACE,
412 DevicePath);
413 if (EFI_ERROR (Status)) {
414 DEBUG ((EFI_D_ERROR, "%a: Failed to install the EFI_DEVICE_PATH "
415 "protocol on a new handle (Status == %r)\n",
416 __FUNCTION__, Status));
417 FreePool (DevicePath);
418 break;
419 }
420
421 Status = VirtioMmioInstallDevice (RegBase, Handle);
422 if (EFI_ERROR (Status)) {
423 DEBUG ((EFI_D_ERROR, "%a: Failed to install VirtIO transport @ 0x%Lx "
424 "on handle %p (Status == %r)\n", __FUNCTION__, RegBase,
425 Handle, Status));
426
427 Status = gBS->UninstallProtocolInterface (Handle,
428 &gEfiDevicePathProtocolGuid, DevicePath);
429 ASSERT_EFI_ERROR (Status);
430 FreePool (DevicePath);
431 }
432 break;
433
434 case PropertyTypeGic:
435 ASSERT (Len == 32);
436
437 DistBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
438 CpuBase = fdt64_to_cpu (((UINT64 *)RegProp)[2]);
439 ASSERT (DistBase < MAX_UINT32);
440 ASSERT (CpuBase < MAX_UINT32);
441
442 PcdSet32 (PcdGicDistributorBase, (UINT32)DistBase);
443 PcdSet32 (PcdGicInterruptInterfaceBase, (UINT32)CpuBase);
444
445 DEBUG ((EFI_D_INFO, "Found GIC @ 0x%Lx/0x%Lx\n", DistBase, CpuBase));
446 break;
447
448 case PropertyTypeGicV3:
449 //
450 // The GIC v3 DT binding describes a series of at least 3 physical (base
451 // addresses, size) pairs: the distributor interface (GICD), at least one
452 // redistributor region (GICR) containing dedicated redistributor
453 // interfaces for all individual CPUs, and the CPU interface (GICC).
454 // Under virtualization, we assume that the first redistributor region
455 // listed covers the boot CPU. Also, our GICv3 driver only supports the
456 // system register CPU interface, so we can safely ignore the MMIO version
457 // which is listed after the sequence of redistributor interfaces.
458 // This means we are only interested in the first two memory regions
459 // supplied, and ignore everything else.
460 //
461 ASSERT (Len >= 32);
462
463 // RegProp[0..1] == { GICD base, GICD size }
464 DistBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
465 ASSERT (DistBase < MAX_UINT32);
466
467 // RegProp[2..3] == { GICR base, GICR size }
468 RedistBase = fdt64_to_cpu (((UINT64 *)RegProp)[2]);
469 ASSERT (RedistBase < MAX_UINT32);
470
471 PcdSet32 (PcdGicDistributorBase, (UINT32)DistBase);
472 PcdSet32 (PcdGicRedistributorsBase, (UINT32)RedistBase);
473
474 DEBUG ((EFI_D_INFO, "Found GIC v3 (re)distributor @ 0x%Lx (0x%Lx)\n",
475 DistBase, RedistBase));
476 break;
477
478 case PropertyTypeRtc:
479 ASSERT (Len == 16);
480
481 RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
482 ASSERT (RegBase < MAX_UINT32);
483
484 PcdSet32 (PcdPL031RtcBase, (UINT32)RegBase);
485
486 DEBUG ((EFI_D_INFO, "Found PL031 RTC @ 0x%Lx\n", RegBase));
487 RtcNode = Node;
488 break;
489
490 case PropertyTypeTimer:
491 //
492 // - interrupts : Interrupt list for secure, non-secure, virtual and
493 // hypervisor timers, in that order.
494 //
495 InterruptProp = fdt_getprop (DeviceTreeBase, Node, "interrupts", &Len);
496 ASSERT (Len == 36 || Len == 48);
497
498 SecIntrNum = fdt32_to_cpu (InterruptProp[0].Number)
499 + (InterruptProp[0].Type ? 16 : 0);
500 IntrNum = fdt32_to_cpu (InterruptProp[1].Number)
501 + (InterruptProp[1].Type ? 16 : 0);
502 VirtIntrNum = fdt32_to_cpu (InterruptProp[2].Number)
503 + (InterruptProp[2].Type ? 16 : 0);
504 HypIntrNum = Len < 48 ? 0 : fdt32_to_cpu (InterruptProp[3].Number)
505 + (InterruptProp[3].Type ? 16 : 0);
506
507 DEBUG ((EFI_D_INFO, "Found Timer interrupts %d, %d, %d, %d\n",
508 SecIntrNum, IntrNum, VirtIntrNum, HypIntrNum));
509
510 PcdSet32 (PcdArmArchTimerSecIntrNum, SecIntrNum);
511 PcdSet32 (PcdArmArchTimerIntrNum, IntrNum);
512 PcdSet32 (PcdArmArchTimerVirtIntrNum, VirtIntrNum);
513 PcdSet32 (PcdArmArchTimerHypIntrNum, HypIntrNum);
514 break;
515
516 case PropertyTypePsci:
517 PsciMethod = fdt_getprop (DeviceTreeBase, Node, "method", &Len);
518
519 if (PsciMethod && AsciiStrnCmp (PsciMethod, "hvc", 3) == 0) {
520 PcdSet32 (PcdArmPsciMethod, 1);
521 } else if (PsciMethod && AsciiStrnCmp (PsciMethod, "smc", 3) == 0) {
522 PcdSet32 (PcdArmPsciMethod, 2);
523 } else {
524 DEBUG ((EFI_D_ERROR, "%a: Unknown PSCI method \"%a\"\n", __FUNCTION__,
525 PsciMethod));
526 }
527 break;
528
529 case PropertyTypeXen:
530 ASSERT (Len == 16);
531
532 //
533 // Retrieve the reg base from this node and wire it up to the
534 // MMIO flavor of the XenBus root device I/O protocol
535 //
536 RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
537 Handle = NULL;
538 Status = XenIoMmioInstall (&Handle, RegBase);
539 if (EFI_ERROR (Status)) {
540 DEBUG ((EFI_D_ERROR, "%a: XenIoMmioInstall () failed on a new handle "
541 "(Status == %r)\n", __FUNCTION__, Status));
542 break;
543 }
544
545 DEBUG ((EFI_D_INFO, "Found Xen node with Grant table @ 0x%Lx\n", RegBase));
546
547 break;
548
549 default:
550 break;
551 }
552 }
553
554 //
555 // UEFI takes ownership of the RTC hardware, and exposes its functionality
556 // through the UEFI Runtime Services GetTime, SetTime, etc. This means we
557 // need to disable it in the device tree to prevent the OS from attaching its
558 // device driver as well.
559 //
560 if ((RtcNode != -1) &&
561 fdt_setprop_string (DeviceTreeBase, RtcNode, "status",
562 "disabled") != 0) {
563 DEBUG ((EFI_D_WARN, "Failed to set PL031 status to 'disabled'\n"));
564 }
565 return EFI_SUCCESS;
566 }