\r
typedef enum {\r
PropertyTypeUnknown,\r
- PropertyTypeGic,\r
PropertyTypeRtc,\r
PropertyTypeVirtio,\r
PropertyTypeUart,\r
- PropertyTypeTimer,\r
- PropertyTypePsci,\r
PropertyTypeFwCfg,\r
PropertyTypePciHost,\r
- PropertyTypeGicV3,\r
PropertyTypeXen,\r
} PROPERTY_TYPE;\r
\r
} PROPERTY;\r
\r
STATIC CONST PROPERTY CompatibleProperties[] = {\r
- { PropertyTypeGic, "arm,cortex-a15-gic" },\r
{ PropertyTypeRtc, "arm,pl031" },\r
{ PropertyTypeVirtio, "virtio,mmio" },\r
{ PropertyTypeUart, "arm,pl011" },\r
- { PropertyTypeTimer, "arm,armv7-timer" },\r
- { PropertyTypeTimer, "arm,armv8-timer" },\r
- { PropertyTypePsci, "arm,psci-0.2" },\r
{ PropertyTypeFwCfg, "qemu,fw-cfg-mmio" },\r
{ PropertyTypePciHost, "pci-host-ecam-generic" },\r
- { PropertyTypeGicV3, "arm,gic-v3" },\r
{ PropertyTypeXen, "xen,xen" },\r
{ PropertyTypeUnknown, "" }\r
};\r
\r
-typedef struct {\r
- UINT32 Type;\r
- UINT32 Number;\r
- UINT32 Flags;\r
-} INTERRUPT_PROPERTY;\r
-\r
STATIC\r
PROPERTY_TYPE\r
GetTypeFromNode (\r
VIRTIO_TRANSPORT_DEVICE_PATH *DevicePath;\r
EFI_HANDLE Handle;\r
UINT64 RegBase;\r
- UINT64 DistBase, CpuBase, RedistBase;\r
- CONST INTERRUPT_PROPERTY *InterruptProp;\r
- INT32 SecIntrNum, IntrNum, VirtIntrNum, HypIntrNum;\r
- CONST CHAR8 *PsciMethod;\r
UINT64 FwCfgSelectorAddress;\r
UINT64 FwCfgSelectorSize;\r
UINT64 FwCfgDataAddress;\r
UINT64 FwCfgDataSize;\r
+ UINT64 FwCfgDmaAddress;\r
+ UINT64 FwCfgDmaSize;\r
+ BOOLEAN HavePci;\r
\r
Hob = GetFirstGuidHob(&gFdtHobGuid);\r
if (Hob == NULL || GET_GUID_HOB_DATA_SIZE (Hob) != sizeof (UINT64)) {\r
return EFI_NOT_FOUND;\r
}\r
\r
- Status = gBS->InstallConfigurationTable (&gFdtTableGuid, DeviceTreeBase);\r
- ASSERT_EFI_ERROR (Status);\r
-\r
DEBUG ((EFI_D_INFO, "%a: DTB @ 0x%p\n", __FUNCTION__, DeviceTreeBase));\r
\r
RtcNode = -1;\r
+ HavePci = FALSE;\r
//\r
// Now enumerate the nodes and install peripherals that we are interested in,\r
// i.e., GIC, RTC and virtio MMIO nodes\r
// TODO use #cells root properties instead\r
//\r
RegProp = fdt_getprop (DeviceTreeBase, Node, "reg", &Len);\r
- ASSERT ((RegProp != NULL) || (PropType == PropertyTypeTimer) ||\r
- (PropType == PropertyTypePsci));\r
+ ASSERT (RegProp != NULL);\r
\r
switch (PropType) {\r
case PropertyTypePciHost:\r
ASSERT (Len == 2 * sizeof (UINT64));\r
Status = ProcessPciHost (DeviceTreeBase, Node, RegProp);\r
ASSERT_EFI_ERROR (Status);\r
+ HavePci = TRUE;\r
break;\r
\r
case PropertyTypeFwCfg:\r
\r
DEBUG ((EFI_D_INFO, "Found FwCfg @ 0x%Lx/0x%Lx\n", FwCfgSelectorAddress,\r
FwCfgDataAddress));\r
+\r
+ if (fdt64_to_cpu (((UINT64 *)RegProp)[1]) >= 0x18) {\r
+ FwCfgDmaAddress = FwCfgDataAddress + 0x10;\r
+ FwCfgDmaSize = 0x08;\r
+\r
+ //\r
+ // See explanation above.\r
+ //\r
+ ASSERT (FwCfgDmaAddress <= MAX_UINTN - FwCfgDmaSize + 1);\r
+\r
+ PcdSet64 (PcdFwCfgDmaAddress, FwCfgDmaAddress);\r
+ DEBUG ((EFI_D_INFO, "Found FwCfg DMA @ 0x%Lx\n", FwCfgDmaAddress));\r
+ }\r
break;\r
\r
case PropertyTypeVirtio:\r
}\r
break;\r
\r
- case PropertyTypeGic:\r
- ASSERT (Len == 32);\r
-\r
- DistBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);\r
- CpuBase = fdt64_to_cpu (((UINT64 *)RegProp)[2]);\r
- ASSERT (DistBase < MAX_UINT32);\r
- ASSERT (CpuBase < MAX_UINT32);\r
-\r
- PcdSet32 (PcdGicDistributorBase, (UINT32)DistBase);\r
- PcdSet32 (PcdGicInterruptInterfaceBase, (UINT32)CpuBase);\r
-\r
- DEBUG ((EFI_D_INFO, "Found GIC @ 0x%Lx/0x%Lx\n", DistBase, CpuBase));\r
- break;\r
-\r
- case PropertyTypeGicV3:\r
- //\r
- // The GIC v3 DT binding describes a series of at least 3 physical (base\r
- // addresses, size) pairs: the distributor interface (GICD), at least one\r
- // redistributor region (GICR) containing dedicated redistributor\r
- // interfaces for all individual CPUs, and the CPU interface (GICC).\r
- // Under virtualization, we assume that the first redistributor region\r
- // listed covers the boot CPU. Also, our GICv3 driver only supports the\r
- // system register CPU interface, so we can safely ignore the MMIO version\r
- // which is listed after the sequence of redistributor interfaces.\r
- // This means we are only interested in the first two memory regions\r
- // supplied, and ignore everything else.\r
- //\r
- ASSERT (Len >= 32);\r
-\r
- // RegProp[0..1] == { GICD base, GICD size }\r
- DistBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);\r
- ASSERT (DistBase < MAX_UINT32);\r
-\r
- // RegProp[2..3] == { GICR base, GICR size }\r
- RedistBase = fdt64_to_cpu (((UINT64 *)RegProp)[2]);\r
- ASSERT (RedistBase < MAX_UINT32);\r
-\r
- PcdSet32 (PcdGicDistributorBase, (UINT32)DistBase);\r
- PcdSet32 (PcdGicRedistributorsBase, (UINT32)RedistBase);\r
-\r
- DEBUG ((EFI_D_INFO, "Found GIC v3 (re)distributor @ 0x%Lx (0x%Lx)\n",\r
- DistBase, RedistBase));\r
- break;\r
-\r
case PropertyTypeRtc:\r
ASSERT (Len == 16);\r
\r
RtcNode = Node;\r
break;\r
\r
- case PropertyTypeTimer:\r
- //\r
- // - interrupts : Interrupt list for secure, non-secure, virtual and\r
- // hypervisor timers, in that order.\r
- //\r
- InterruptProp = fdt_getprop (DeviceTreeBase, Node, "interrupts", &Len);\r
- ASSERT (Len == 36 || Len == 48);\r
-\r
- SecIntrNum = fdt32_to_cpu (InterruptProp[0].Number)\r
- + (InterruptProp[0].Type ? 16 : 0);\r
- IntrNum = fdt32_to_cpu (InterruptProp[1].Number)\r
- + (InterruptProp[1].Type ? 16 : 0);\r
- VirtIntrNum = fdt32_to_cpu (InterruptProp[2].Number)\r
- + (InterruptProp[2].Type ? 16 : 0);\r
- HypIntrNum = Len < 48 ? 0 : fdt32_to_cpu (InterruptProp[3].Number)\r
- + (InterruptProp[3].Type ? 16 : 0);\r
-\r
- DEBUG ((EFI_D_INFO, "Found Timer interrupts %d, %d, %d, %d\n",\r
- SecIntrNum, IntrNum, VirtIntrNum, HypIntrNum));\r
-\r
- PcdSet32 (PcdArmArchTimerSecIntrNum, SecIntrNum);\r
- PcdSet32 (PcdArmArchTimerIntrNum, IntrNum);\r
- PcdSet32 (PcdArmArchTimerVirtIntrNum, VirtIntrNum);\r
- PcdSet32 (PcdArmArchTimerHypIntrNum, HypIntrNum);\r
- break;\r
-\r
- case PropertyTypePsci:\r
- PsciMethod = fdt_getprop (DeviceTreeBase, Node, "method", &Len);\r
-\r
- if (PsciMethod && AsciiStrnCmp (PsciMethod, "hvc", 3) == 0) {\r
- PcdSet32 (PcdArmPsciMethod, 1);\r
- } else if (PsciMethod && AsciiStrnCmp (PsciMethod, "smc", 3) == 0) {\r
- PcdSet32 (PcdArmPsciMethod, 2);\r
- } else {\r
- DEBUG ((EFI_D_ERROR, "%a: Unknown PSCI method \"%a\"\n", __FUNCTION__,\r
- PsciMethod));\r
- }\r
- break;\r
-\r
case PropertyTypeXen:\r
ASSERT (Len == 16);\r
\r
}\r
}\r
\r
- //\r
- // UEFI takes ownership of the RTC hardware, and exposes its functionality\r
- // through the UEFI Runtime Services GetTime, SetTime, etc. This means we\r
- // need to disable it in the device tree to prevent the OS from attaching its\r
- // device driver as well.\r
- //\r
- if ((RtcNode != -1) &&\r
- fdt_setprop_string (DeviceTreeBase, RtcNode, "status",\r
- "disabled") != 0) {\r
- DEBUG ((EFI_D_WARN, "Failed to set PL031 status to 'disabled'\n"));\r
+ if (!FeaturePcdGet (PcdPureAcpiBoot)) {\r
+ //\r
+ // Only install the FDT as a configuration table if we want to leave it up\r
+ // to the OS to decide whether it prefers ACPI over DT.\r
+ //\r
+ Status = gBS->InstallConfigurationTable (&gFdtTableGuid, DeviceTreeBase);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // UEFI takes ownership of the RTC hardware, and exposes its functionality\r
+ // through the UEFI Runtime Services GetTime, SetTime, etc. This means we\r
+ // need to disable it in the device tree to prevent the OS from attaching its\r
+ // device driver as well.\r
+ //\r
+ if ((RtcNode != -1) &&\r
+ fdt_setprop_string (DeviceTreeBase, RtcNode, "status",\r
+ "disabled") != 0) {\r
+ DEBUG ((EFI_D_WARN, "Failed to set PL031 status to 'disabled'\n"));\r
+ }\r
+\r
+ if (HavePci) {\r
+ //\r
+ // Set the /chosen/linux,pci-probe-only property to 1, so that the PCI\r
+ // setup we will perform in the firmware is honored by the Linux OS,\r
+ // rather than torn down and done from scratch. This is generally a more\r
+ // sensible approach, and aligns with what ACPI based OSes do in general.\r
+ //\r
+ // In case we are exposing an emulated VGA PCI device to the guest, which\r
+ // may subsequently get exposed via the Graphics Output protocol and\r
+ // driven as an efifb by Linux, we need this setting to prevent the\r
+ // framebuffer from becoming unresponsive.\r
+ //\r
+ Node = fdt_path_offset (DeviceTreeBase, "/chosen");\r
+ if (Node < 0) {\r
+ Node = fdt_add_subnode (DeviceTreeBase, 0, "/chosen");\r
+ }\r
+ if (Node < 0 ||\r
+ fdt_setprop_u32 (DeviceTreeBase, Node, "linux,pci-probe-only", 1) < 0) {\r
+ DEBUG ((EFI_D_WARN, "Failed to set /chosen/linux,pci-probe-only property\n"));\r
+ }\r
+ }\r
}\r
return EFI_SUCCESS;\r
}\r