qemu

Форк
0
/
viot.c 
142 строки · 4.5 Кб
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

13
struct viot_pci_host_range {
14
    int min_bus;
15
    int max_bus;
16
};
17

18
static void build_pci_host_range(GArray *table_data, int min_bus, int max_bus,
19
                                 uint16_t output_node)
20
{
21
    /* Type */
22
    build_append_int_noprefix(table_data, 1 /* PCI range */, 1);
23
    /* Reserved */
24
    build_append_int_noprefix(table_data, 0, 1);
25
    /* Length */
26
    build_append_int_noprefix(table_data, 24, 2);
27
    /* Endpoint start */
28
    build_append_int_noprefix(table_data, PCI_BUILD_BDF(min_bus, 0), 4);
29
    /* PCI Segment start */
30
    build_append_int_noprefix(table_data, 0, 2);
31
    /* PCI Segment end */
32
    build_append_int_noprefix(table_data, 0, 2);
33
    /* PCI BDF start */
34
    build_append_int_noprefix(table_data, PCI_BUILD_BDF(min_bus, 0), 2);
35
    /* PCI BDF end */
36
    build_append_int_noprefix(table_data, PCI_BUILD_BDF(max_bus, 0xff), 2);
37
    /* Output node */
38
    build_append_int_noprefix(table_data, output_node, 2);
39
    /* Reserved */
40
    build_append_int_noprefix(table_data, 0, 6);
41
}
42

43
/* Build PCI range for a given PCI host bridge */
44
static int enumerate_pci_host_bridges(Object *obj, void *opaque)
45
{
46
    GArray *pci_host_ranges = opaque;
47

48
    if (object_dynamic_cast(obj, TYPE_PCI_HOST_BRIDGE)) {
49
        PCIBus *bus = PCI_HOST_BRIDGE(obj)->bus;
50

51
        if (bus && !pci_bus_bypass_iommu(bus)) {
52
            int min_bus, max_bus;
53

54
            pci_bus_range(bus, &min_bus, &max_bus);
55

56
            const struct viot_pci_host_range pci_host_range = {
57
                .min_bus = min_bus,
58
                .max_bus = max_bus,
59
            };
60
            g_array_append_val(pci_host_ranges, pci_host_range);
61
        }
62
    }
63

64
    return 0;
65
}
66

67
static gint pci_host_range_compare(gconstpointer a, gconstpointer b)
68
{
69
    struct viot_pci_host_range *range_a = (struct viot_pci_host_range *)a;
70
    struct viot_pci_host_range *range_b = (struct viot_pci_host_range *)b;
71

72
    if (range_a->min_bus < range_b->min_bus) {
73
        return -1;
74
    } else if (range_a->min_bus > range_b->min_bus) {
75
        return 1;
76
    } else {
77
        return 0;
78
    }
79
}
80

81
/*
82
 * Generate a VIOT table with one PCI-based virtio-iommu that manages PCI
83
 * endpoints.
84
 *
85
 * Defined in the ACPI Specification (Version TBD)
86
 */
87
void build_viot(MachineState *ms, GArray *table_data, BIOSLinker *linker,
88
                uint16_t virtio_iommu_bdf, const char *oem_id,
89
                const char *oem_table_id)
90
{
91
    /* The virtio-iommu node follows the 48-bytes header */
92
    int viommu_off = 48;
93
    AcpiTable table = { .sig = "VIOT", .rev = 0,
94
                        .oem_id = oem_id, .oem_table_id = oem_table_id };
95
    GArray *pci_host_ranges =  g_array_new(false, true,
96
                                           sizeof(struct viot_pci_host_range));
97
    struct viot_pci_host_range *pci_host_range;
98
    int i;
99

100
    /* Build the list of PCI ranges that this viommu manages */
101
    object_child_foreach_recursive(OBJECT(ms), enumerate_pci_host_bridges,
102
                                   pci_host_ranges);
103

104
    /* Sort the pci host ranges by min_bus */
105
    g_array_sort(pci_host_ranges, pci_host_range_compare);
106

107
    /* ACPI table header */
108
    acpi_table_begin(&table, table_data);
109
    /* Node count */
110
    build_append_int_noprefix(table_data, pci_host_ranges->len + 1, 2);
111
    /* Node offset */
112
    build_append_int_noprefix(table_data, viommu_off, 2);
113
    /* Reserved */
114
    build_append_int_noprefix(table_data, 0, 8);
115

116
    /* Virtio-iommu node */
117
    /* Type */
118
    build_append_int_noprefix(table_data, 3 /* virtio-pci IOMMU */, 1);
119
    /* Reserved */
120
    build_append_int_noprefix(table_data, 0, 1);
121
    /* Length */
122
    build_append_int_noprefix(table_data, 16, 2);
123
    /* PCI Segment */
124
    build_append_int_noprefix(table_data, 0, 2);
125
    /* PCI BDF number */
126
    build_append_int_noprefix(table_data, virtio_iommu_bdf, 2);
127
    /* Reserved */
128
    build_append_int_noprefix(table_data, 0, 8);
129

130
    /* PCI ranges found above */
131
    for (i = 0; i < pci_host_ranges->len; i++) {
132
        pci_host_range = &g_array_index(pci_host_ranges,
133
                                        struct viot_pci_host_range, i);
134

135
        build_pci_host_range(table_data, pci_host_range->min_bus,
136
                             pci_host_range->max_bus, viommu_off);
137
    }
138

139
    g_array_free(pci_host_ranges, true);
140

141
    acpi_table_end(linker, &table);
142
}
143

144

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.