qemu/hw/acpi/viot.c
<<
>>
Prefs
   1/*
   2 * ACPI Virtual I/O Translation table implementation
   3 *
   4 * SPDX-License-Identifier: GPL-2.0-or-later
   5 */
   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"
  12
  13struct viot_pci_ranges {
  14    GArray *blob;
  15    size_t count;
  16    uint16_t output_node;
  17};
  18
  19/* Build PCI range for a given PCI host bridge */
  20static int build_pci_range_node(Object *obj, void *opaque)
  21{
  22    struct viot_pci_ranges *pci_ranges = opaque;
  23    GArray *blob = pci_ranges->blob;
  24
  25    if (object_dynamic_cast(obj, TYPE_PCI_HOST_BRIDGE)) {
  26        PCIBus *bus = PCI_HOST_BRIDGE(obj)->bus;
  27
  28        if (bus && !pci_bus_bypass_iommu(bus)) {
  29            int min_bus, max_bus;
  30
  31            pci_bus_range(bus, &min_bus, &max_bus);
  32
  33            /* Type */
  34            build_append_int_noprefix(blob, 1 /* PCI range */, 1);
  35            /* Reserved */
  36            build_append_int_noprefix(blob, 0, 1);
  37            /* Length */
  38            build_append_int_noprefix(blob, 24, 2);
  39            /* Endpoint start */
  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);
  43            /* PCI Segment end */
  44            build_append_int_noprefix(blob, 0, 2);
  45            /* PCI BDF start */
  46            build_append_int_noprefix(blob, PCI_BUILD_BDF(min_bus, 0), 2);
  47            /* PCI BDF end */
  48            build_append_int_noprefix(blob, PCI_BUILD_BDF(max_bus, 0xff), 2);
  49            /* Output node */
  50            build_append_int_noprefix(blob, pci_ranges->output_node, 2);
  51            /* Reserved */
  52            build_append_int_noprefix(blob, 0, 6);
  53
  54            pci_ranges->count++;
  55        }
  56    }
  57
  58    return 0;
  59}
  60
  61/*
  62 * Generate a VIOT table with one PCI-based virtio-iommu that manages PCI
  63 * endpoints.
  64 *
  65 * Defined in the ACPI Specification (Version TBD)
  66 */
  67void 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)
  70{
  71    /* The virtio-iommu node follows the 48-bytes header */
  72    int viommu_off = 48;
  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),
  78    };
  79
  80    /* Build the list of PCI ranges that this viommu manages */
  81    object_child_foreach_recursive(OBJECT(ms), build_pci_range_node,
  82                                   &pci_ranges);
  83
  84    /* ACPI table header */
  85    acpi_table_begin(&table, table_data);
  86    /* Node count */
  87    build_append_int_noprefix(table_data, pci_ranges.count + 1, 2);
  88    /* Node offset */
  89    build_append_int_noprefix(table_data, viommu_off, 2);
  90    /* Reserved */
  91    build_append_int_noprefix(table_data, 0, 8);
  92
  93    /* Virtio-iommu node */
  94    /* Type */
  95    build_append_int_noprefix(table_data, 3 /* virtio-pci IOMMU */, 1);
  96    /* Reserved */
  97    build_append_int_noprefix(table_data, 0, 1);
  98    /* Length */
  99    build_append_int_noprefix(table_data, 16, 2);
 100    /* PCI Segment */
 101    build_append_int_noprefix(table_data, 0, 2);
 102    /* PCI BDF number */
 103    build_append_int_noprefix(table_data, virtio_iommu_bdf, 2);
 104    /* Reserved */
 105    build_append_int_noprefix(table_data, 0, 8);
 106
 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);
 111
 112    acpi_table_end(linker, &table);
 113}
 114
 115