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