qemu

Форк
0
/
virt-acpi-build.c 
819 строк · 29.7 Кб
1
/*
2
 * Support for generating ACPI tables and passing them to Guests
3
 *
4
 * RISC-V virt ACPI generation
5
 *
6
 * Copyright (C) 2008-2010  Kevin O'Connor <kevin@koconnor.net>
7
 * Copyright (C) 2006 Fabrice Bellard
8
 * Copyright (C) 2013 Red Hat Inc
9
 * Copyright (c) 2015 HUAWEI TECHNOLOGIES CO.,LTD.
10
 * Copyright (C) 2021-2023 Ventana Micro Systems Inc
11
 *
12
 * This program is free software; you can redistribute it and/or modify
13
 * it under the terms of the GNU General Public License as published by
14
 * the Free Software Foundation; either version 2 of the License, or
15
 * (at your option) any later version.
16

17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU General Public License for more details.
21

22
 * You should have received a copy of the GNU General Public License along
23
 * with this program; if not, see <http://www.gnu.org/licenses/>.
24
 */
25

26
#include "qemu/osdep.h"
27
#include "hw/acpi/acpi-defs.h"
28
#include "hw/acpi/acpi.h"
29
#include "hw/acpi/aml-build.h"
30
#include "hw/acpi/pci.h"
31
#include "hw/acpi/utils.h"
32
#include "hw/intc/riscv_aclint.h"
33
#include "hw/nvram/fw_cfg_acpi.h"
34
#include "hw/pci-host/gpex.h"
35
#include "hw/riscv/virt.h"
36
#include "hw/riscv/numa.h"
37
#include "hw/virtio/virtio-acpi.h"
38
#include "migration/vmstate.h"
39
#include "qapi/error.h"
40
#include "qemu/error-report.h"
41
#include "sysemu/reset.h"
42

43
#define ACPI_BUILD_TABLE_SIZE             0x20000
44
#define ACPI_BUILD_INTC_ID(socket, index) ((socket << 24) | (index))
45

46
typedef struct AcpiBuildState {
47
    /* Copy of table in RAM (for patching) */
48
    MemoryRegion *table_mr;
49
    MemoryRegion *rsdp_mr;
50
    MemoryRegion *linker_mr;
51
    /* Is table patched? */
52
    bool patched;
53
} AcpiBuildState;
54

55
static void acpi_align_size(GArray *blob, unsigned align)
56
{
57
    /*
58
     * Align size to multiple of given size. This reduces the chance
59
     * we need to change size in the future (breaking cross version migration).
60
     */
61
    g_array_set_size(blob, ROUND_UP(acpi_data_len(blob), align));
62
}
63

64
static void riscv_acpi_madt_add_rintc(uint32_t uid,
65
                                      const CPUArchIdList *arch_ids,
66
                                      GArray *entry,
67
                                      RISCVVirtState *s)
68
{
69
    uint8_t  guest_index_bits = imsic_num_bits(s->aia_guests + 1);
70
    uint64_t hart_id = arch_ids->cpus[uid].arch_id;
71
    uint32_t imsic_size, local_cpu_id, socket_id;
72
    uint64_t imsic_socket_addr, imsic_addr;
73
    MachineState *ms = MACHINE(s);
74

75
    socket_id = arch_ids->cpus[uid].props.node_id;
76
    local_cpu_id = (arch_ids->cpus[uid].arch_id -
77
                    riscv_socket_first_hartid(ms, socket_id)) %
78
                    riscv_socket_hart_count(ms, socket_id);
79
    imsic_socket_addr = s->memmap[VIRT_IMSIC_S].base +
80
                        (socket_id * VIRT_IMSIC_GROUP_MAX_SIZE);
81
    imsic_size = IMSIC_HART_SIZE(guest_index_bits);
82
    imsic_addr = imsic_socket_addr + local_cpu_id * imsic_size;
83
    build_append_int_noprefix(entry, 0x18, 1);       /* Type     */
84
    build_append_int_noprefix(entry, 36, 1);         /* Length   */
85
    build_append_int_noprefix(entry, 1, 1);          /* Version  */
86
    build_append_int_noprefix(entry, 0, 1);          /* Reserved */
87
    build_append_int_noprefix(entry, 0x1, 4);        /* Flags    */
88
    build_append_int_noprefix(entry, hart_id, 8);    /* Hart ID  */
89
    build_append_int_noprefix(entry, uid, 4);        /* ACPI Processor UID */
90
    /* External Interrupt Controller ID */
91
    if (s->aia_type == VIRT_AIA_TYPE_APLIC) {
92
        build_append_int_noprefix(entry,
93
                                  ACPI_BUILD_INTC_ID(
94
                                      arch_ids->cpus[uid].props.node_id,
95
                                      local_cpu_id),
96
                                  4);
97
    } else if (s->aia_type == VIRT_AIA_TYPE_NONE) {
98
        build_append_int_noprefix(entry,
99
                                  ACPI_BUILD_INTC_ID(
100
                                      arch_ids->cpus[uid].props.node_id,
101
                                      2 * local_cpu_id + 1),
102
                                  4);
103
    } else {
104
        build_append_int_noprefix(entry, 0, 4);
105
    }
106

107
    if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) {
108
        /* IMSIC Base address */
109
        build_append_int_noprefix(entry, imsic_addr, 8);
110
        /* IMSIC Size */
111
        build_append_int_noprefix(entry, imsic_size, 4);
112
    } else {
113
        build_append_int_noprefix(entry, 0, 8);
114
        build_append_int_noprefix(entry, 0, 4);
115
    }
116
}
117

118
static void acpi_dsdt_add_cpus(Aml *scope, RISCVVirtState *s)
119
{
120
    MachineClass *mc = MACHINE_GET_CLASS(s);
121
    MachineState *ms = MACHINE(s);
122
    const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms);
123

124
    for (int i = 0; i < arch_ids->len; i++) {
125
            Aml *dev;
126
            GArray *madt_buf = g_array_new(0, 1, 1);
127

128
            dev = aml_device("C%.03X", i);
129
            aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0007")));
130
            aml_append(dev, aml_name_decl("_UID",
131
                       aml_int(arch_ids->cpus[i].arch_id)));
132

133
            /* build _MAT object */
134
            riscv_acpi_madt_add_rintc(i, arch_ids, madt_buf, s);
135
            aml_append(dev, aml_name_decl("_MAT",
136
                                          aml_buffer(madt_buf->len,
137
                                          (uint8_t *)madt_buf->data)));
138
            g_array_free(madt_buf, true);
139

140
            aml_append(scope, dev);
141
    }
142
}
143

144
static void acpi_dsdt_add_plic_aplic(Aml *scope, uint8_t socket_count,
145
                                     uint64_t mmio_base, uint64_t mmio_size,
146
                                     const char *hid)
147
{
148
    uint64_t plic_aplic_addr;
149
    uint32_t gsi_base;
150
    uint8_t  socket;
151

152
    for (socket = 0; socket < socket_count; socket++) {
153
        plic_aplic_addr = mmio_base + mmio_size * socket;
154
        gsi_base = VIRT_IRQCHIP_NUM_SOURCES * socket;
155
        Aml *dev = aml_device("IC%.02X", socket);
156
        aml_append(dev, aml_name_decl("_HID", aml_string("%s", hid)));
157
        aml_append(dev, aml_name_decl("_UID", aml_int(socket)));
158
        aml_append(dev, aml_name_decl("_GSB", aml_int(gsi_base)));
159

160
        Aml *crs = aml_resource_template();
161
        aml_append(crs, aml_memory32_fixed(plic_aplic_addr, mmio_size,
162
                                           AML_READ_WRITE));
163
        aml_append(dev, aml_name_decl("_CRS", crs));
164
        aml_append(scope, dev);
165
    }
166
}
167

168
static void
169
acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap,
170
                    uint32_t uart_irq)
171
{
172
    Aml *dev = aml_device("COM0");
173
    aml_append(dev, aml_name_decl("_HID", aml_string("RSCV0003")));
174
    aml_append(dev, aml_name_decl("_UID", aml_int(0)));
175

176
    Aml *crs = aml_resource_template();
177
    aml_append(crs, aml_memory32_fixed(uart_memmap->base,
178
                                         uart_memmap->size, AML_READ_WRITE));
179
    aml_append(crs,
180
                aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
181
                               AML_EXCLUSIVE, &uart_irq, 1));
182
    aml_append(dev, aml_name_decl("_CRS", crs));
183

184
    Aml *pkg = aml_package(2);
185
    aml_append(pkg, aml_string("clock-frequency"));
186
    aml_append(pkg, aml_int(3686400));
187

188
    Aml *UUID = aml_touuid("DAFFD814-6EBA-4D8C-8A91-BC9BBF4AA301");
189

190
    Aml *pkg1 = aml_package(1);
191
    aml_append(pkg1, pkg);
192

193
    Aml *package = aml_package(2);
194
    aml_append(package, UUID);
195
    aml_append(package, pkg1);
196

197
    aml_append(dev, aml_name_decl("_DSD", package));
198
    aml_append(scope, dev);
199
}
200

201
/*
202
 * Serial Port Console Redirection Table (SPCR)
203
 * Rev: 1.07
204
 */
205

206
static void
207
spcr_setup(GArray *table_data, BIOSLinker *linker, RISCVVirtState *s)
208
{
209
    AcpiSpcrData serial = {
210
        .interface_type = 0,       /* 16550 compatible */
211
        .base_addr.id = AML_AS_SYSTEM_MEMORY,
212
        .base_addr.width = 32,
213
        .base_addr.offset = 0,
214
        .base_addr.size = 1,
215
        .base_addr.addr = s->memmap[VIRT_UART0].base,
216
        .interrupt_type = (1 << 4),/* Bit[4] RISC-V PLIC/APLIC */
217
        .pc_interrupt = 0,
218
        .interrupt = UART0_IRQ,
219
        .baud_rate = 7,            /* 15200 */
220
        .parity = 0,
221
        .stop_bits = 1,
222
        .flow_control = 0,
223
        .terminal_type = 3,        /* ANSI */
224
        .language = 0,             /* Language */
225
        .pci_device_id = 0xffff,   /* not a PCI device*/
226
        .pci_vendor_id = 0xffff,   /* not a PCI device*/
227
        .pci_bus = 0,
228
        .pci_device = 0,
229
        .pci_function = 0,
230
        .pci_flags = 0,
231
        .pci_segment = 0,
232
    };
233

234
    build_spcr(table_data, linker, &serial, 2, s->oem_id, s->oem_table_id);
235
}
236

237
/* RHCT Node[N] starts at offset 56 */
238
#define RHCT_NODE_ARRAY_OFFSET 56
239

240
/*
241
 * ACPI spec, Revision 6.5+
242
 * 5.2.36 RISC-V Hart Capabilities Table (RHCT)
243
 * REF: https://github.com/riscv-non-isa/riscv-acpi/issues/16
244
 *      https://drive.google.com/file/d/1nP3nFiH4jkPMp6COOxP6123DCZKR-tia/view
245
 *      https://drive.google.com/file/d/1sKbOa8m1UZw1JkquZYe3F1zQBN1xXsaf/view
246
 */
247
static void build_rhct(GArray *table_data,
248
                       BIOSLinker *linker,
249
                       RISCVVirtState *s)
250
{
251
    MachineClass *mc = MACHINE_GET_CLASS(s);
252
    MachineState *ms = MACHINE(s);
253
    const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms);
254
    size_t len, aligned_len;
255
    uint32_t isa_offset, num_rhct_nodes, cmo_offset = 0;
256
    RISCVCPU *cpu = &s->soc[0].harts[0];
257
    uint32_t mmu_offset = 0;
258
    uint8_t satp_mode_max;
259
    g_autofree char *isa = NULL;
260

261
    AcpiTable table = { .sig = "RHCT", .rev = 1, .oem_id = s->oem_id,
262
                        .oem_table_id = s->oem_table_id };
263

264
    acpi_table_begin(&table, table_data);
265

266
    build_append_int_noprefix(table_data, 0x0, 4);   /* Reserved */
267

268
    /* Time Base Frequency */
269
    build_append_int_noprefix(table_data,
270
                              RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, 8);
271

272
    /* ISA + N hart info */
273
    num_rhct_nodes = 1 + ms->smp.cpus;
274
    if (cpu->cfg.ext_zicbom || cpu->cfg.ext_zicboz) {
275
        num_rhct_nodes++;
276
    }
277

278
    if (cpu->cfg.satp_mode.supported != 0) {
279
        num_rhct_nodes++;
280
    }
281

282
    /* Number of RHCT nodes*/
283
    build_append_int_noprefix(table_data, num_rhct_nodes, 4);
284

285
    /* Offset to the RHCT node array */
286
    build_append_int_noprefix(table_data, RHCT_NODE_ARRAY_OFFSET, 4);
287

288
    /* ISA String Node */
289
    isa_offset = table_data->len - table.table_offset;
290
    build_append_int_noprefix(table_data, 0, 2);   /* Type 0 */
291

292
    isa = riscv_isa_string(cpu);
293
    len = 8 + strlen(isa) + 1;
294
    aligned_len = (len % 2) ? (len + 1) : len;
295

296
    build_append_int_noprefix(table_data, aligned_len, 2);   /* Length */
297
    build_append_int_noprefix(table_data, 0x1, 2);           /* Revision */
298

299
    /* ISA string length including NUL */
300
    build_append_int_noprefix(table_data, strlen(isa) + 1, 2);
301
    g_array_append_vals(table_data, isa, strlen(isa) + 1);   /* ISA string */
302

303
    if (aligned_len != len) {
304
        build_append_int_noprefix(table_data, 0x0, 1);   /* Optional Padding */
305
    }
306

307
    /* CMO node */
308
    if (cpu->cfg.ext_zicbom || cpu->cfg.ext_zicboz) {
309
        cmo_offset = table_data->len - table.table_offset;
310
        build_append_int_noprefix(table_data, 1, 2);    /* Type */
311
        build_append_int_noprefix(table_data, 10, 2);   /* Length */
312
        build_append_int_noprefix(table_data, 0x1, 2);  /* Revision */
313
        build_append_int_noprefix(table_data, 0, 1);    /* Reserved */
314

315
        /* CBOM block size */
316
        if (cpu->cfg.cbom_blocksize) {
317
            build_append_int_noprefix(table_data,
318
                                      __builtin_ctz(cpu->cfg.cbom_blocksize),
319
                                      1);
320
        } else {
321
            build_append_int_noprefix(table_data, 0, 1);
322
        }
323

324
        /* CBOP block size */
325
        build_append_int_noprefix(table_data, 0, 1);
326

327
        /* CBOZ block size */
328
        if (cpu->cfg.cboz_blocksize) {
329
            build_append_int_noprefix(table_data,
330
                                      __builtin_ctz(cpu->cfg.cboz_blocksize),
331
                                      1);
332
        } else {
333
            build_append_int_noprefix(table_data, 0, 1);
334
        }
335
    }
336

337
    /* MMU node structure */
338
    if (cpu->cfg.satp_mode.supported != 0) {
339
        satp_mode_max = satp_mode_max_from_map(cpu->cfg.satp_mode.map);
340
        mmu_offset = table_data->len - table.table_offset;
341
        build_append_int_noprefix(table_data, 2, 2);    /* Type */
342
        build_append_int_noprefix(table_data, 8, 2);    /* Length */
343
        build_append_int_noprefix(table_data, 0x1, 2);  /* Revision */
344
        build_append_int_noprefix(table_data, 0, 1);    /* Reserved */
345
        /* MMU Type */
346
        if (satp_mode_max == VM_1_10_SV57) {
347
            build_append_int_noprefix(table_data, 2, 1);    /* Sv57 */
348
        } else if (satp_mode_max == VM_1_10_SV48) {
349
            build_append_int_noprefix(table_data, 1, 1);    /* Sv48 */
350
        } else if (satp_mode_max == VM_1_10_SV39) {
351
            build_append_int_noprefix(table_data, 0, 1);    /* Sv39 */
352
        } else {
353
            assert(1);
354
        }
355
    }
356

357
    /* Hart Info Node */
358
    for (int i = 0; i < arch_ids->len; i++) {
359
        len = 16;
360
        int num_offsets = 1;
361
        build_append_int_noprefix(table_data, 0xFFFF, 2);  /* Type */
362

363
        /* Length */
364
        if (cmo_offset) {
365
            len += 4;
366
            num_offsets++;
367
        }
368

369
        if (mmu_offset) {
370
            len += 4;
371
            num_offsets++;
372
        }
373

374
        build_append_int_noprefix(table_data, len, 2);
375
        build_append_int_noprefix(table_data, 0x1, 2); /* Revision */
376
        /* Number of offsets */
377
        build_append_int_noprefix(table_data, num_offsets, 2);
378
        build_append_int_noprefix(table_data, i, 4);   /* ACPI Processor UID */
379
        /* Offsets */
380
        build_append_int_noprefix(table_data, isa_offset, 4);
381
        if (cmo_offset) {
382
            build_append_int_noprefix(table_data, cmo_offset, 4);
383
        }
384

385
        if (mmu_offset) {
386
            build_append_int_noprefix(table_data, mmu_offset, 4);
387
        }
388
    }
389

390
    acpi_table_end(linker, &table);
391
}
392

393
/* FADT */
394
static void build_fadt_rev6(GArray *table_data,
395
                            BIOSLinker *linker,
396
                            RISCVVirtState *s,
397
                            unsigned dsdt_tbl_offset)
398
{
399
    AcpiFadtData fadt = {
400
        .rev = 6,
401
        .minor_ver = 5,
402
        .flags = 1 << ACPI_FADT_F_HW_REDUCED_ACPI,
403
        .xdsdt_tbl_offset = &dsdt_tbl_offset,
404
    };
405

406
    build_fadt(table_data, linker, &fadt, s->oem_id, s->oem_table_id);
407
}
408

409
/* DSDT */
410
static void build_dsdt(GArray *table_data,
411
                       BIOSLinker *linker,
412
                       RISCVVirtState *s)
413
{
414
    Aml *scope, *dsdt;
415
    MachineState *ms = MACHINE(s);
416
    uint8_t socket_count;
417
    const MemMapEntry *memmap = s->memmap;
418
    AcpiTable table = { .sig = "DSDT", .rev = 2, .oem_id = s->oem_id,
419
                        .oem_table_id = s->oem_table_id };
420

421

422
    acpi_table_begin(&table, table_data);
423
    dsdt = init_aml_allocator();
424

425
    /*
426
     * When booting the VM with UEFI, UEFI takes ownership of the RTC hardware.
427
     * While UEFI can use libfdt to disable the RTC device node in the DTB that
428
     * it passes to the OS, it cannot modify AML. Therefore, we won't generate
429
     * the RTC ACPI device at all when using UEFI.
430
     */
431
    scope = aml_scope("\\_SB");
432
    acpi_dsdt_add_cpus(scope, s);
433

434
    fw_cfg_acpi_dsdt_add(scope, &memmap[VIRT_FW_CFG]);
435

436
    socket_count = riscv_socket_count(ms);
437

438
    if (s->aia_type == VIRT_AIA_TYPE_NONE) {
439
        acpi_dsdt_add_plic_aplic(scope, socket_count, memmap[VIRT_PLIC].base,
440
                                 memmap[VIRT_PLIC].size, "RSCV0001");
441
    } else {
442
        acpi_dsdt_add_plic_aplic(scope, socket_count, memmap[VIRT_APLIC_S].base,
443
                                 memmap[VIRT_APLIC_S].size, "RSCV0002");
444
    }
445

446
    acpi_dsdt_add_uart(scope, &memmap[VIRT_UART0], UART0_IRQ);
447

448
    if (socket_count == 1) {
449
        virtio_acpi_dsdt_add(scope, memmap[VIRT_VIRTIO].base,
450
                             memmap[VIRT_VIRTIO].size,
451
                             VIRTIO_IRQ, 0, VIRTIO_COUNT);
452
        acpi_dsdt_add_gpex_host(scope, PCIE_IRQ);
453
    } else if (socket_count == 2) {
454
        virtio_acpi_dsdt_add(scope, memmap[VIRT_VIRTIO].base,
455
                             memmap[VIRT_VIRTIO].size,
456
                             VIRTIO_IRQ + VIRT_IRQCHIP_NUM_SOURCES, 0,
457
                             VIRTIO_COUNT);
458
        acpi_dsdt_add_gpex_host(scope, PCIE_IRQ + VIRT_IRQCHIP_NUM_SOURCES);
459
    } else {
460
        virtio_acpi_dsdt_add(scope, memmap[VIRT_VIRTIO].base,
461
                             memmap[VIRT_VIRTIO].size,
462
                             VIRTIO_IRQ + VIRT_IRQCHIP_NUM_SOURCES, 0,
463
                             VIRTIO_COUNT);
464
        acpi_dsdt_add_gpex_host(scope, PCIE_IRQ + VIRT_IRQCHIP_NUM_SOURCES * 2);
465
    }
466

467
    aml_append(dsdt, scope);
468

469
    /* copy AML table into ACPI tables blob and patch header there */
470
    g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len);
471

472
    acpi_table_end(linker, &table);
473
    free_aml_allocator();
474
}
475

476
/*
477
 * ACPI spec, Revision 6.5+
478
 * 5.2.12 Multiple APIC Description Table (MADT)
479
 * REF: https://github.com/riscv-non-isa/riscv-acpi/issues/15
480
 *      https://drive.google.com/file/d/1R6k4MshhN3WTT-hwqAquu5nX6xSEqK2l/view
481
 *      https://drive.google.com/file/d/1oMGPyOD58JaPgMl1pKasT-VKsIKia7zR/view
482
 */
483
static void build_madt(GArray *table_data,
484
                       BIOSLinker *linker,
485
                       RISCVVirtState *s)
486
{
487
    MachineClass *mc = MACHINE_GET_CLASS(s);
488
    MachineState *ms = MACHINE(s);
489
    const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms);
490
    uint8_t  group_index_bits = imsic_num_bits(riscv_socket_count(ms));
491
    uint8_t  guest_index_bits = imsic_num_bits(s->aia_guests + 1);
492
    uint16_t imsic_max_hart_per_socket = 0;
493
    uint8_t  hart_index_bits;
494
    uint64_t aplic_addr;
495
    uint32_t gsi_base;
496
    uint8_t  socket;
497

498
    for (socket = 0; socket < riscv_socket_count(ms); socket++) {
499
        if (imsic_max_hart_per_socket < s->soc[socket].num_harts) {
500
            imsic_max_hart_per_socket = s->soc[socket].num_harts;
501
        }
502
    }
503

504
    hart_index_bits = imsic_num_bits(imsic_max_hart_per_socket);
505

506
    AcpiTable table = { .sig = "APIC", .rev = 6, .oem_id = s->oem_id,
507
                        .oem_table_id = s->oem_table_id };
508

509
    acpi_table_begin(&table, table_data);
510
    /* Local Interrupt Controller Address */
511
    build_append_int_noprefix(table_data, 0, 4);
512
    build_append_int_noprefix(table_data, 0, 4);   /* MADT Flags */
513

514
    /* RISC-V Local INTC structures per HART */
515
    for (int i = 0; i < arch_ids->len; i++) {
516
        riscv_acpi_madt_add_rintc(i, arch_ids, table_data, s);
517
    }
518

519
    /* IMSIC */
520
    if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) {
521
        /* IMSIC */
522
        build_append_int_noprefix(table_data, 0x19, 1);     /* Type */
523
        build_append_int_noprefix(table_data, 16, 1);       /* Length */
524
        build_append_int_noprefix(table_data, 1, 1);        /* Version */
525
        build_append_int_noprefix(table_data, 0, 1);        /* Reserved */
526
        build_append_int_noprefix(table_data, 0, 4);        /* Flags */
527
        /* Number of supervisor mode Interrupt Identities */
528
        build_append_int_noprefix(table_data, VIRT_IRQCHIP_NUM_MSIS, 2);
529
        /* Number of guest mode Interrupt Identities */
530
        build_append_int_noprefix(table_data, VIRT_IRQCHIP_NUM_MSIS, 2);
531
        /* Guest Index Bits */
532
        build_append_int_noprefix(table_data, guest_index_bits, 1);
533
        /* Hart Index Bits */
534
        build_append_int_noprefix(table_data, hart_index_bits, 1);
535
        /* Group Index Bits */
536
        build_append_int_noprefix(table_data, group_index_bits, 1);
537
        /* Group Index Shift */
538
        build_append_int_noprefix(table_data, IMSIC_MMIO_GROUP_MIN_SHIFT, 1);
539
    }
540

541
    if (s->aia_type != VIRT_AIA_TYPE_NONE) {
542
        /* APLICs */
543
        for (socket = 0; socket < riscv_socket_count(ms); socket++) {
544
            aplic_addr = s->memmap[VIRT_APLIC_S].base +
545
                             s->memmap[VIRT_APLIC_S].size * socket;
546
            gsi_base = VIRT_IRQCHIP_NUM_SOURCES * socket;
547
            build_append_int_noprefix(table_data, 0x1A, 1);    /* Type */
548
            build_append_int_noprefix(table_data, 36, 1);      /* Length */
549
            build_append_int_noprefix(table_data, 1, 1);       /* Version */
550
            build_append_int_noprefix(table_data, socket, 1);  /* APLIC ID */
551
            build_append_int_noprefix(table_data, 0, 4);       /* Flags */
552
            build_append_int_noprefix(table_data, 0, 8);       /* Hardware ID */
553
            /* Number of IDCs */
554
            if (s->aia_type == VIRT_AIA_TYPE_APLIC) {
555
                build_append_int_noprefix(table_data,
556
                                          s->soc[socket].num_harts,
557
                                          2);
558
            } else {
559
                build_append_int_noprefix(table_data, 0, 2);
560
            }
561
            /* Total External Interrupt Sources Supported */
562
            build_append_int_noprefix(table_data, VIRT_IRQCHIP_NUM_SOURCES, 2);
563
            /* Global System Interrupt Base */
564
            build_append_int_noprefix(table_data, gsi_base, 4);
565
            /* APLIC Address */
566
            build_append_int_noprefix(table_data, aplic_addr, 8);
567
            /* APLIC size */
568
            build_append_int_noprefix(table_data,
569
                                      s->memmap[VIRT_APLIC_S].size, 4);
570
        }
571
    } else {
572
        /* PLICs */
573
        for (socket = 0; socket < riscv_socket_count(ms); socket++) {
574
            aplic_addr = s->memmap[VIRT_PLIC].base +
575
                         s->memmap[VIRT_PLIC].size * socket;
576
            gsi_base = VIRT_IRQCHIP_NUM_SOURCES * socket;
577
            build_append_int_noprefix(table_data, 0x1B, 1);   /* Type */
578
            build_append_int_noprefix(table_data, 36, 1);     /* Length */
579
            build_append_int_noprefix(table_data, 1, 1);      /* Version */
580
            build_append_int_noprefix(table_data, socket, 1); /* PLIC ID */
581
            build_append_int_noprefix(table_data, 0, 8);      /* Hardware ID */
582
            /* Total External Interrupt Sources Supported */
583
            build_append_int_noprefix(table_data,
584
                                      VIRT_IRQCHIP_NUM_SOURCES - 1, 2);
585
            build_append_int_noprefix(table_data, 0, 2);     /* Max Priority */
586
            build_append_int_noprefix(table_data, 0, 4);     /* Flags */
587
            /* PLIC Size */
588
            build_append_int_noprefix(table_data, s->memmap[VIRT_PLIC].size, 4);
589
            /* PLIC Address */
590
            build_append_int_noprefix(table_data, aplic_addr, 8);
591
            /* Global System Interrupt Vector Base */
592
            build_append_int_noprefix(table_data, gsi_base, 4);
593
        }
594
    }
595

596
    acpi_table_end(linker, &table);
597
}
598

599
/*
600
 * ACPI spec, Revision 6.5+
601
 * 5.2.16 System Resource Affinity Table (SRAT)
602
 * REF: https://github.com/riscv-non-isa/riscv-acpi/issues/25
603
 *      https://drive.google.com/file/d/1YTdDx2IPm5IeZjAW932EYU-tUtgS08tX/view
604
 */
605
static void
606
build_srat(GArray *table_data, BIOSLinker *linker, RISCVVirtState *vms)
607
{
608
    int i;
609
    uint64_t mem_base;
610
    MachineClass *mc = MACHINE_GET_CLASS(vms);
611
    MachineState *ms = MACHINE(vms);
612
    const CPUArchIdList *cpu_list = mc->possible_cpu_arch_ids(ms);
613
    AcpiTable table = { .sig = "SRAT", .rev = 3, .oem_id = vms->oem_id,
614
                        .oem_table_id = vms->oem_table_id };
615

616
    acpi_table_begin(&table, table_data);
617
    build_append_int_noprefix(table_data, 1, 4); /* Reserved */
618
    build_append_int_noprefix(table_data, 0, 8); /* Reserved */
619

620
    for (i = 0; i < cpu_list->len; ++i) {
621
        uint32_t nodeid = cpu_list->cpus[i].props.node_id;
622
        /*
623
         * 5.2.16.8 RINTC Affinity Structure
624
         */
625
        build_append_int_noprefix(table_data, 7, 1);      /* Type */
626
        build_append_int_noprefix(table_data, 20, 1);     /* Length */
627
        build_append_int_noprefix(table_data, 0, 2);        /* Reserved */
628
        build_append_int_noprefix(table_data, nodeid, 4); /* Proximity Domain */
629
        build_append_int_noprefix(table_data, i, 4); /* ACPI Processor UID */
630
        /* Flags, Table 5-70 */
631
        build_append_int_noprefix(table_data, 1 /* Flags: Enabled */, 4);
632
        build_append_int_noprefix(table_data, 0, 4); /* Clock Domain */
633
    }
634

635
    mem_base = vms->memmap[VIRT_DRAM].base;
636
    for (i = 0; i < ms->numa_state->num_nodes; ++i) {
637
        if (ms->numa_state->nodes[i].node_mem > 0) {
638
            build_srat_memory(table_data, mem_base,
639
                              ms->numa_state->nodes[i].node_mem, i,
640
                              MEM_AFFINITY_ENABLED);
641
            mem_base += ms->numa_state->nodes[i].node_mem;
642
        }
643
    }
644

645
    acpi_table_end(linker, &table);
646
}
647

648
static void virt_acpi_build(RISCVVirtState *s, AcpiBuildTables *tables)
649
{
650
    GArray *table_offsets;
651
    unsigned dsdt, xsdt;
652
    GArray *tables_blob = tables->table_data;
653
    MachineState *ms = MACHINE(s);
654

655
    table_offsets = g_array_new(false, true,
656
                                sizeof(uint32_t));
657

658
    bios_linker_loader_alloc(tables->linker,
659
                             ACPI_BUILD_TABLE_FILE, tables_blob,
660
                             64, false);
661

662
    /* DSDT is pointed to by FADT */
663
    dsdt = tables_blob->len;
664
    build_dsdt(tables_blob, tables->linker, s);
665

666
    /* FADT and others pointed to by XSDT */
667
    acpi_add_table(table_offsets, tables_blob);
668
    build_fadt_rev6(tables_blob, tables->linker, s, dsdt);
669

670
    acpi_add_table(table_offsets, tables_blob);
671
    build_madt(tables_blob, tables->linker, s);
672

673
    acpi_add_table(table_offsets, tables_blob);
674
    build_rhct(tables_blob, tables->linker, s);
675

676
    acpi_add_table(table_offsets, tables_blob);
677
    spcr_setup(tables_blob, tables->linker, s);
678

679
    acpi_add_table(table_offsets, tables_blob);
680
    {
681
        AcpiMcfgInfo mcfg = {
682
           .base = s->memmap[VIRT_PCIE_ECAM].base,
683
           .size = s->memmap[VIRT_PCIE_ECAM].size,
684
        };
685
        build_mcfg(tables_blob, tables->linker, &mcfg, s->oem_id,
686
                   s->oem_table_id);
687
    }
688

689
    if (ms->numa_state->num_nodes > 0) {
690
        acpi_add_table(table_offsets, tables_blob);
691
        build_srat(tables_blob, tables->linker, s);
692
        if (ms->numa_state->have_numa_distance) {
693
            acpi_add_table(table_offsets, tables_blob);
694
            build_slit(tables_blob, tables->linker, ms, s->oem_id,
695
                       s->oem_table_id);
696
        }
697
    }
698

699
    /* XSDT is pointed to by RSDP */
700
    xsdt = tables_blob->len;
701
    build_xsdt(tables_blob, tables->linker, table_offsets, s->oem_id,
702
                s->oem_table_id);
703

704
    /* RSDP is in FSEG memory, so allocate it separately */
705
    {
706
        AcpiRsdpData rsdp_data = {
707
            .revision = 2,
708
            .oem_id = s->oem_id,
709
            .xsdt_tbl_offset = &xsdt,
710
            .rsdt_tbl_offset = NULL,
711
        };
712
        build_rsdp(tables->rsdp, tables->linker, &rsdp_data);
713
    }
714

715
    /*
716
     * The align size is 128, warn if 64k is not enough therefore
717
     * the align size could be resized.
718
     */
719
    if (tables_blob->len > ACPI_BUILD_TABLE_SIZE / 2) {
720
        warn_report("ACPI table size %u exceeds %d bytes,"
721
                    " migration may not work",
722
                    tables_blob->len, ACPI_BUILD_TABLE_SIZE / 2);
723
        error_printf("Try removing some objects.");
724
    }
725

726
    acpi_align_size(tables_blob, ACPI_BUILD_TABLE_SIZE);
727

728
    /* Clean up memory that's no longer used */
729
    g_array_free(table_offsets, true);
730
}
731

732
static void acpi_ram_update(MemoryRegion *mr, GArray *data)
733
{
734
    uint32_t size = acpi_data_len(data);
735

736
    /*
737
     * Make sure RAM size is correct - in case it got changed
738
     * e.g. by migration
739
     */
740
    memory_region_ram_resize(mr, size, &error_abort);
741

742
    memcpy(memory_region_get_ram_ptr(mr), data->data, size);
743
    memory_region_set_dirty(mr, 0, size);
744
}
745

746
static void virt_acpi_build_update(void *build_opaque)
747
{
748
    AcpiBuildState *build_state = build_opaque;
749
    AcpiBuildTables tables;
750

751
    /* No state to update or already patched? Nothing to do. */
752
    if (!build_state || build_state->patched) {
753
        return;
754
    }
755

756
    build_state->patched = true;
757

758
    acpi_build_tables_init(&tables);
759

760
    virt_acpi_build(RISCV_VIRT_MACHINE(qdev_get_machine()), &tables);
761

762
    acpi_ram_update(build_state->table_mr, tables.table_data);
763
    acpi_ram_update(build_state->rsdp_mr, tables.rsdp);
764
    acpi_ram_update(build_state->linker_mr, tables.linker->cmd_blob);
765

766
    acpi_build_tables_cleanup(&tables, true);
767
}
768

769
static void virt_acpi_build_reset(void *build_opaque)
770
{
771
    AcpiBuildState *build_state = build_opaque;
772
    build_state->patched = false;
773
}
774

775
static const VMStateDescription vmstate_virt_acpi_build = {
776
    .name = "virt_acpi_build",
777
    .version_id = 1,
778
    .minimum_version_id = 1,
779
    .fields = (const VMStateField[]) {
780
        VMSTATE_BOOL(patched, AcpiBuildState),
781
        VMSTATE_END_OF_LIST()
782
    },
783
};
784

785
void virt_acpi_setup(RISCVVirtState *s)
786
{
787
    AcpiBuildTables tables;
788
    AcpiBuildState *build_state;
789

790
    build_state = g_malloc0(sizeof *build_state);
791

792
    acpi_build_tables_init(&tables);
793
    virt_acpi_build(s, &tables);
794

795
    /* Now expose it all to Guest */
796
    build_state->table_mr = acpi_add_rom_blob(virt_acpi_build_update,
797
                                              build_state, tables.table_data,
798
                                              ACPI_BUILD_TABLE_FILE);
799
    assert(build_state->table_mr != NULL);
800

801
    build_state->linker_mr = acpi_add_rom_blob(virt_acpi_build_update,
802
                                               build_state,
803
                                               tables.linker->cmd_blob,
804
                                               ACPI_BUILD_LOADER_FILE);
805

806
    build_state->rsdp_mr = acpi_add_rom_blob(virt_acpi_build_update,
807
                                             build_state, tables.rsdp,
808
                                             ACPI_BUILD_RSDP_FILE);
809

810
    qemu_register_reset(virt_acpi_build_reset, build_state);
811
    virt_acpi_build_reset(build_state);
812
    vmstate_register(NULL, 0, &vmstate_virt_acpi_build, build_state);
813

814
    /*
815
     * Clean up tables but don't free the memory: we track it
816
     * in build_state.
817
     */
818
    acpi_build_tables_cleanup(&tables, false);
819
}
820

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

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

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

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