2 * ACPI Virtual I/O Translation table implementation
4 * SPDX-License-Identifier: GPL-2.0-or-later
6 #include "qemu/osdep.h"
7 #include "hw/acpi/acpi.h"
8 #include "hw/acpi/aml-build.h"
9 #include "hw/acpi/viot.h"
10 #include "hw/pci/pci.h"
11 #include "hw/pci/pci_host.h"
13 struct viot_pci_ranges
{
19 /* Build PCI range for a given PCI host bridge */
20 static int build_pci_range_node(Object
*obj
, void *opaque
)
22 struct viot_pci_ranges
*pci_ranges
= opaque
;
23 GArray
*blob
= pci_ranges
->blob
;
25 if (object_dynamic_cast(obj
, TYPE_PCI_HOST_BRIDGE
)) {
26 PCIBus
*bus
= PCI_HOST_BRIDGE(obj
)->bus
;
28 if (bus
&& !pci_bus_bypass_iommu(bus
)) {
31 pci_bus_range(bus
, &min_bus
, &max_bus
);
34 build_append_int_noprefix(blob
, 1 /* PCI range */, 1);
36 build_append_int_noprefix(blob
, 0, 1);
38 build_append_int_noprefix(blob
, 24, 2);
40 build_append_int_noprefix(blob
, PCI_BUILD_BDF(min_bus
, 0), 4);
41 /* PCI Segment start */
42 build_append_int_noprefix(blob
, 0, 2);
44 build_append_int_noprefix(blob
, 0, 2);
46 build_append_int_noprefix(blob
, PCI_BUILD_BDF(min_bus
, 0), 2);
48 build_append_int_noprefix(blob
, PCI_BUILD_BDF(max_bus
, 0xff), 2);
50 build_append_int_noprefix(blob
, pci_ranges
->output_node
, 2);
52 build_append_int_noprefix(blob
, 0, 6);
62 * Generate a VIOT table with one PCI-based virtio-iommu that manages PCI
65 * Defined in the ACPI Specification (Version TBD)
67 void build_viot(MachineState
*ms
, GArray
*table_data
, BIOSLinker
*linker
,
68 uint16_t virtio_iommu_bdf
, const char *oem_id
,
69 const char *oem_table_id
)
71 /* The virtio-iommu node follows the 48-bytes header */
73 AcpiTable table
= { .sig
= "VIOT", .rev
= 0,
74 .oem_id
= oem_id
, .oem_table_id
= oem_table_id
};
75 struct viot_pci_ranges pci_ranges
= {
76 .output_node
= viommu_off
,
77 .blob
= g_array_new(false, true /* clear */, 1),
80 /* Build the list of PCI ranges that this viommu manages */
81 object_child_foreach_recursive(OBJECT(ms
), build_pci_range_node
,
84 /* ACPI table header */
85 acpi_table_begin(&table
, table_data
);
87 build_append_int_noprefix(table_data
, pci_ranges
.count
+ 1, 2);
89 build_append_int_noprefix(table_data
, viommu_off
, 2);
91 build_append_int_noprefix(table_data
, 0, 8);
93 /* Virtio-iommu node */
95 build_append_int_noprefix(table_data
, 3 /* virtio-pci IOMMU */, 1);
97 build_append_int_noprefix(table_data
, 0, 1);
99 build_append_int_noprefix(table_data
, 16, 2);
101 build_append_int_noprefix(table_data
, 0, 2);
103 build_append_int_noprefix(table_data
, virtio_iommu_bdf
, 2);
105 build_append_int_noprefix(table_data
, 0, 8);
107 /* PCI ranges found above */
108 g_array_append_vals(table_data
, pci_ranges
.blob
->data
,
109 pci_ranges
.blob
->len
);
110 g_array_free(pci_ranges
.blob
, true);
112 acpi_table_end(linker
, &table
);