microvm: add acpi support
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABCgAGBQJfY2pCAAoJEEy22O7T6HE4LegQANGeb7oAWgdD6rI9aFQTD6zK tU3jjfIbt/xsxnbnWVlNeouoxwKTJUiBxmVNgPPZdgXYd7GgKn8qZe5ccnnF6TX2 n9+GCV1Jvc7clBMVvj3EceSaKQrd859i2mXc85YEeC6T/Hcq9zSwDN9UTCeQYOCZ 27r6wzWpL2sU6/vHXzb24VSZzKl91uQAekFI7WM7z+/fv3kz5KGff2zzq2Rp+77s do5MU++fcnAmz31c9vBoT9v5tvNWe6xXu79Fn2ay9orDj/uThkF+PqGGVQiyxeOi 6E2X321AhMxSUqVgev1j0O+ZcxECxXoK8/7RQu72JLbTUPBAyC8jyuFATuMbQd7Z xS5WNBEe0Qo7zA1ZBvpnQyPrW21Wi95mON9GPrk0ixH0ECl6Bb+vMRunBK6tiUtw 635qi73VfpNbu4fi7CBQwd/9+LDfgVb3+uEoO0EEL5WWbK9XjoklK+7chGbu4RFg H0or5yvX2CbR7z52W+HXNMuseUFvIQrJ8taOla8AoS/I9cKxj+j99AEYv8MNMVwe rRvJF0iL/hl1pdgeOm+noRDG9ledefYxscvUdVAs+5rdiOEMKDbNbm+Ff6BKfM5N 8rTS7d6s8PXFql/YTc1CLTQmMh2q6RpiSO929mKFQc+MiQOBzwWP5tCpFOy1ywMQ 0sxmqx24FzwVakd22k7/ =IWLS -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kraxel/tags/microvm-20200917-pull-request' into staging microvm: add acpi support # gpg: Signature made Thu 17 Sep 2020 14:53:06 BST # gpg: using RSA key 4CB6D8EED3E87138 # gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" [full] # gpg: aka "Gerd Hoffmann <gerd@kraxel.org>" [full] # gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>" [full] # Primary key fingerprint: A032 8CFF B93A 17A7 9901 FE7D 4CB6 D8EE D3E8 7138 * remotes/kraxel/tags/microvm-20200917-pull-request: (21 commits) microvm: enable ramfb tests/acpi: update expected data files for microvm tests/acpi: add microvm test tests/acpi: allow override blkdev tests/acpi: allow microvm test data updates. microvm: wire up hotplug x86: move cpu hotplug from pc to x86 x86: move acpi_dev from pc/microvm x86: constify x86_machine_is_*_enabled microvm/acpi: disable virtio-mmio cmdline hack microvm/acpi: use seabios with acpi=on microvm/acpi: use GSI 16-23 for virtio microvm/acpi: add acpi_dsdt_add_virtio() for x86 microvm/acpi: add minimal acpi support microvm: make virtio irq base runtime configurable acpi: move acpi_dsdt_add_power_button() to ged acpi: ged: add x86 device variant. acpi: ged: add control regs seabios: add bios-microvm.bin binary seabios: add microvm config, update build rules ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
a6a0c8394c
@ -20,6 +20,7 @@
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "sysemu/runstate.h"
|
||||
|
||||
static const uint32_t ged_supported_events[] = {
|
||||
ACPI_GED_MEM_HOTPLUG_EVT,
|
||||
@ -141,6 +142,14 @@ void build_ged_aml(Aml *table, const char *name, HotplugHandler *hotplug_dev,
|
||||
aml_append(table, dev);
|
||||
}
|
||||
|
||||
void acpi_dsdt_add_power_button(Aml *scope)
|
||||
{
|
||||
Aml *dev = aml_device(ACPI_POWER_BUTTON_DEVICE);
|
||||
aml_append(dev, aml_name_decl("_HID", aml_string("PNP0C0C")));
|
||||
aml_append(dev, aml_name_decl("_UID", aml_int(0)));
|
||||
aml_append(scope, dev);
|
||||
}
|
||||
|
||||
/* Memory read by the GED _EVT AML dynamic method */
|
||||
static uint64_t ged_evt_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
@ -176,6 +185,45 @@ static const MemoryRegionOps ged_evt_ops = {
|
||||
},
|
||||
};
|
||||
|
||||
static uint64_t ged_regs_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ged_regs_write(void *opaque, hwaddr addr, uint64_t data,
|
||||
unsigned int size)
|
||||
{
|
||||
bool slp_en;
|
||||
int slp_typ;
|
||||
|
||||
switch (addr) {
|
||||
case ACPI_GED_REG_SLEEP_CTL:
|
||||
slp_typ = (data >> 2) & 0x07;
|
||||
slp_en = (data >> 5) & 0x01;
|
||||
if (slp_en && slp_typ == 5) {
|
||||
qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
|
||||
}
|
||||
return;
|
||||
case ACPI_GED_REG_SLEEP_STS:
|
||||
return;
|
||||
case ACPI_GED_REG_RESET:
|
||||
if (data == ACPI_GED_RESET_VALUE) {
|
||||
qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps ged_regs_ops = {
|
||||
.read = ged_regs_read,
|
||||
.write = ged_regs_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
@ -332,6 +380,10 @@ static void acpi_ged_initfn(Object *obj)
|
||||
sysbus_init_mmio(sbd, &s->container_memhp);
|
||||
acpi_memory_hotplug_init(&s->container_memhp, OBJECT(dev),
|
||||
&s->memhp_state, 0);
|
||||
|
||||
memory_region_init_io(&ged_st->regs, obj, &ged_regs_ops, ged_st,
|
||||
TYPE_ACPI_GED "-regs", ACPI_GED_REG_COUNT);
|
||||
sysbus_init_mmio(sbd, &ged_st->regs);
|
||||
}
|
||||
|
||||
static void acpi_ged_class_init(ObjectClass *class, void *data)
|
||||
|
@ -357,14 +357,6 @@ static void acpi_dsdt_add_gpio(Aml *scope, const MemMapEntry *gpio_memmap,
|
||||
aml_append(scope, dev);
|
||||
}
|
||||
|
||||
static void acpi_dsdt_add_power_button(Aml *scope)
|
||||
{
|
||||
Aml *dev = aml_device(ACPI_POWER_BUTTON_DEVICE);
|
||||
aml_append(dev, aml_name_decl("_HID", aml_string("PNP0C0C")));
|
||||
aml_append(dev, aml_name_decl("_UID", aml_int(0)));
|
||||
aml_append(scope, dev);
|
||||
}
|
||||
|
||||
static void acpi_dsdt_add_tpm(Aml *scope, VirtMachineState *vms)
|
||||
{
|
||||
PlatformBusDevice *pbus = PLATFORM_BUS_DEVICE(vms->platform_bus_dev);
|
||||
|
@ -103,6 +103,7 @@ config MICROVM
|
||||
select I8259
|
||||
select MC146818RTC
|
||||
select VIRTIO_MMIO
|
||||
select ACPI_HW_REDUCED
|
||||
|
||||
config X86_IOMMU
|
||||
bool
|
||||
|
@ -2431,7 +2431,7 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
|
||||
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
acpi_build_madt(tables_blob, tables->linker, x86ms,
|
||||
ACPI_DEVICE_IF(pcms->acpi_dev), true);
|
||||
ACPI_DEVICE_IF(x86ms->acpi_dev), true);
|
||||
|
||||
vmgenid_dev = find_vmgenid_dev();
|
||||
if (vmgenid_dev) {
|
||||
|
240
hw/i386/acpi-microvm.c
Normal file
240
hw/i386/acpi-microvm.c
Normal file
@ -0,0 +1,240 @@
|
||||
/* Support for generating ACPI tables and passing them to Guests
|
||||
*
|
||||
* Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
|
||||
* Copyright (C) 2006 Fabrice Bellard
|
||||
* Copyright (C) 2013 Red Hat Inc
|
||||
*
|
||||
* Author: Michael S. Tsirkin <mst@redhat.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
#include "exec/memory.h"
|
||||
#include "hw/acpi/acpi.h"
|
||||
#include "hw/acpi/aml-build.h"
|
||||
#include "hw/acpi/bios-linker-loader.h"
|
||||
#include "hw/acpi/generic_event_device.h"
|
||||
#include "hw/acpi/utils.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/i386/fw_cfg.h"
|
||||
#include "hw/i386/microvm.h"
|
||||
#include "hw/virtio/virtio-mmio.h"
|
||||
|
||||
#include "acpi-common.h"
|
||||
#include "acpi-microvm.h"
|
||||
|
||||
static void acpi_dsdt_add_virtio(Aml *scope,
|
||||
MicrovmMachineState *mms)
|
||||
{
|
||||
gchar *separator;
|
||||
long int index;
|
||||
BusState *bus;
|
||||
BusChild *kid;
|
||||
|
||||
bus = sysbus_get_default();
|
||||
QTAILQ_FOREACH(kid, &bus->children, sibling) {
|
||||
DeviceState *dev = kid->child;
|
||||
Object *obj = object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MMIO);
|
||||
|
||||
if (obj) {
|
||||
VirtIOMMIOProxy *mmio = VIRTIO_MMIO(obj);
|
||||
VirtioBusState *mmio_virtio_bus = &mmio->bus;
|
||||
BusState *mmio_bus = &mmio_virtio_bus->parent_obj;
|
||||
|
||||
if (QTAILQ_EMPTY(&mmio_bus->children)) {
|
||||
continue;
|
||||
}
|
||||
separator = g_strrstr(mmio_bus->name, ".");
|
||||
if (!separator) {
|
||||
continue;
|
||||
}
|
||||
if (qemu_strtol(separator + 1, NULL, 10, &index) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t irq = mms->virtio_irq_base + index;
|
||||
hwaddr base = VIRTIO_MMIO_BASE + index * 512;
|
||||
hwaddr size = 512;
|
||||
|
||||
Aml *dev = aml_device("VR%02u", (unsigned)index);
|
||||
aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0005")));
|
||||
aml_append(dev, aml_name_decl("_UID", aml_int(index)));
|
||||
aml_append(dev, aml_name_decl("_CCA", aml_int(1)));
|
||||
|
||||
Aml *crs = aml_resource_template();
|
||||
aml_append(crs, aml_memory32_fixed(base, size, AML_READ_WRITE));
|
||||
aml_append(crs,
|
||||
aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
|
||||
AML_EXCLUSIVE, &irq, 1));
|
||||
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||
aml_append(scope, dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
build_dsdt_microvm(GArray *table_data, BIOSLinker *linker,
|
||||
MicrovmMachineState *mms)
|
||||
{
|
||||
X86MachineState *x86ms = X86_MACHINE(mms);
|
||||
Aml *dsdt, *sb_scope, *scope, *pkg;
|
||||
bool ambiguous;
|
||||
Object *isabus;
|
||||
|
||||
isabus = object_resolve_path_type("", TYPE_ISA_BUS, &ambiguous);
|
||||
assert(isabus);
|
||||
assert(!ambiguous);
|
||||
|
||||
dsdt = init_aml_allocator();
|
||||
|
||||
/* Reserve space for header */
|
||||
acpi_data_push(dsdt->buf, sizeof(AcpiTableHeader));
|
||||
|
||||
sb_scope = aml_scope("_SB");
|
||||
fw_cfg_add_acpi_dsdt(sb_scope, x86ms->fw_cfg);
|
||||
isa_build_aml(ISA_BUS(isabus), sb_scope);
|
||||
build_ged_aml(sb_scope, GED_DEVICE, x86ms->acpi_dev,
|
||||
GED_MMIO_IRQ, AML_SYSTEM_MEMORY, GED_MMIO_BASE);
|
||||
acpi_dsdt_add_power_button(sb_scope);
|
||||
acpi_dsdt_add_virtio(sb_scope, mms);
|
||||
aml_append(dsdt, sb_scope);
|
||||
|
||||
/* ACPI 5.0: Table 7-209 System State Package */
|
||||
scope = aml_scope("\\");
|
||||
pkg = aml_package(4);
|
||||
aml_append(pkg, aml_int(ACPI_GED_SLP_TYP_S5));
|
||||
aml_append(pkg, aml_int(0)); /* ignored */
|
||||
aml_append(pkg, aml_int(0)); /* reserved */
|
||||
aml_append(pkg, aml_int(0)); /* reserved */
|
||||
aml_append(scope, aml_name_decl("_S5", pkg));
|
||||
aml_append(dsdt, scope);
|
||||
|
||||
/* copy AML table into ACPI tables blob and patch header there */
|
||||
g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len);
|
||||
build_header(linker, table_data,
|
||||
(void *)(table_data->data + table_data->len - dsdt->buf->len),
|
||||
"DSDT", dsdt->buf->len, 2, NULL, NULL);
|
||||
free_aml_allocator();
|
||||
}
|
||||
|
||||
static void acpi_build_microvm(AcpiBuildTables *tables,
|
||||
MicrovmMachineState *mms)
|
||||
{
|
||||
MachineState *machine = MACHINE(mms);
|
||||
X86MachineState *x86ms = X86_MACHINE(mms);
|
||||
GArray *table_offsets;
|
||||
GArray *tables_blob = tables->table_data;
|
||||
unsigned dsdt, xsdt;
|
||||
AcpiFadtData pmfadt = {
|
||||
/* ACPI 5.0: 4.1 Hardware-Reduced ACPI */
|
||||
.rev = 5,
|
||||
.flags = ((1 << ACPI_FADT_F_HW_REDUCED_ACPI) |
|
||||
(1 << ACPI_FADT_F_RESET_REG_SUP)),
|
||||
|
||||
/* ACPI 5.0: 4.8.3.7 Sleep Control and Status Registers */
|
||||
.sleep_ctl = {
|
||||
.space_id = AML_AS_SYSTEM_MEMORY,
|
||||
.bit_width = 8,
|
||||
.address = GED_MMIO_BASE_REGS + ACPI_GED_REG_SLEEP_CTL,
|
||||
},
|
||||
.sleep_sts = {
|
||||
.space_id = AML_AS_SYSTEM_MEMORY,
|
||||
.bit_width = 8,
|
||||
.address = GED_MMIO_BASE_REGS + ACPI_GED_REG_SLEEP_STS,
|
||||
},
|
||||
|
||||
/* ACPI 5.0: 4.8.3.6 Reset Register */
|
||||
.reset_reg = {
|
||||
.space_id = AML_AS_SYSTEM_MEMORY,
|
||||
.bit_width = 8,
|
||||
.address = GED_MMIO_BASE_REGS + ACPI_GED_REG_RESET,
|
||||
},
|
||||
.reset_val = ACPI_GED_RESET_VALUE,
|
||||
};
|
||||
|
||||
table_offsets = g_array_new(false, true /* clear */,
|
||||
sizeof(uint32_t));
|
||||
bios_linker_loader_alloc(tables->linker,
|
||||
ACPI_BUILD_TABLE_FILE, tables_blob,
|
||||
64 /* Ensure FACS is aligned */,
|
||||
false /* high memory */);
|
||||
|
||||
dsdt = tables_blob->len;
|
||||
build_dsdt_microvm(tables_blob, tables->linker, mms);
|
||||
|
||||
pmfadt.dsdt_tbl_offset = &dsdt;
|
||||
pmfadt.xdsdt_tbl_offset = &dsdt;
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_fadt(tables_blob, tables->linker, &pmfadt, NULL, NULL);
|
||||
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
acpi_build_madt(tables_blob, tables->linker, X86_MACHINE(machine),
|
||||
ACPI_DEVICE_IF(x86ms->acpi_dev), false);
|
||||
|
||||
xsdt = tables_blob->len;
|
||||
build_xsdt(tables_blob, tables->linker, table_offsets, NULL, NULL);
|
||||
|
||||
/* RSDP is in FSEG memory, so allocate it separately */
|
||||
{
|
||||
AcpiRsdpData rsdp_data = {
|
||||
/* ACPI 2.0: 5.2.4.3 RSDP Structure */
|
||||
.revision = 2, /* xsdt needs v2 */
|
||||
.oem_id = ACPI_BUILD_APPNAME6,
|
||||
.xsdt_tbl_offset = &xsdt,
|
||||
.rsdt_tbl_offset = NULL,
|
||||
};
|
||||
build_rsdp(tables->rsdp, tables->linker, &rsdp_data);
|
||||
}
|
||||
|
||||
/* Cleanup memory that's no longer used. */
|
||||
g_array_free(table_offsets, true);
|
||||
}
|
||||
|
||||
static void acpi_build_no_update(void *build_opaque)
|
||||
{
|
||||
/* nothing, microvm tables don't change at runtime */
|
||||
}
|
||||
|
||||
void acpi_setup_microvm(MicrovmMachineState *mms)
|
||||
{
|
||||
X86MachineState *x86ms = X86_MACHINE(mms);
|
||||
AcpiBuildTables tables;
|
||||
|
||||
assert(x86ms->fw_cfg);
|
||||
|
||||
if (!x86_machine_is_acpi_enabled(x86ms)) {
|
||||
return;
|
||||
}
|
||||
|
||||
acpi_build_tables_init(&tables);
|
||||
acpi_build_microvm(&tables, mms);
|
||||
|
||||
/* Now expose it all to Guest */
|
||||
acpi_add_rom_blob(acpi_build_no_update, NULL,
|
||||
tables.table_data,
|
||||
ACPI_BUILD_TABLE_FILE,
|
||||
ACPI_BUILD_TABLE_MAX_SIZE);
|
||||
acpi_add_rom_blob(acpi_build_no_update, NULL,
|
||||
tables.linker->cmd_blob,
|
||||
"etc/table-loader", 0);
|
||||
acpi_add_rom_blob(acpi_build_no_update, NULL,
|
||||
tables.rsdp,
|
||||
ACPI_BUILD_RSDP_FILE, 0);
|
||||
|
||||
acpi_build_tables_cleanup(&tables, false);
|
||||
}
|
8
hw/i386/acpi-microvm.h
Normal file
8
hw/i386/acpi-microvm.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef HW_I386_ACPI_MICROVM_H
|
||||
#define HW_I386_ACPI_MICROVM_H
|
||||
|
||||
#include "hw/i386/microvm.h"
|
||||
|
||||
void acpi_setup_microvm(MicrovmMachineState *mms);
|
||||
|
||||
#endif
|
36
hw/i386/generic_event_device_x86.c
Normal file
36
hw/i386/generic_event_device_x86.c
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* x86 variant of the generic event device for hw reduced acpi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2 or later, as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/acpi/generic_event_device.h"
|
||||
#include "hw/i386/pc.h"
|
||||
|
||||
static void acpi_ged_x86_class_init(ObjectClass *class, void *data)
|
||||
{
|
||||
AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(class);
|
||||
|
||||
adevc->madt_cpu = pc_madt_cpu_entry;
|
||||
}
|
||||
|
||||
static const TypeInfo acpi_ged_x86_info = {
|
||||
.name = TYPE_ACPI_GED_X86,
|
||||
.parent = TYPE_ACPI_GED,
|
||||
.class_init = acpi_ged_x86_class_init,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ TYPE_HOTPLUG_HANDLER },
|
||||
{ TYPE_ACPI_DEVICE_IF },
|
||||
{ }
|
||||
}
|
||||
};
|
||||
|
||||
static void acpi_ged_x86_register_types(void)
|
||||
{
|
||||
type_register_static(&acpi_ged_x86_info);
|
||||
}
|
||||
|
||||
type_init(acpi_ged_x86_register_types)
|
@ -11,13 +11,14 @@ i386_ss.add(when: 'CONFIG_X86_IOMMU', if_true: files('x86-iommu.c'),
|
||||
if_false: files('x86-iommu-stub.c'))
|
||||
i386_ss.add(when: 'CONFIG_AMD_IOMMU', if_true: files('amd_iommu.c'))
|
||||
i386_ss.add(when: 'CONFIG_I440FX', if_true: files('pc_piix.c'))
|
||||
i386_ss.add(when: 'CONFIG_MICROVM', if_true: files('microvm.c'))
|
||||
i386_ss.add(when: 'CONFIG_MICROVM', if_true: files('microvm.c', 'acpi-microvm.c'))
|
||||
i386_ss.add(when: 'CONFIG_Q35', if_true: files('pc_q35.c'))
|
||||
i386_ss.add(when: 'CONFIG_VMMOUSE', if_true: files('vmmouse.c'))
|
||||
i386_ss.add(when: 'CONFIG_VMPORT', if_true: files('vmport.c'))
|
||||
i386_ss.add(when: 'CONFIG_VTD', if_true: files('intel_iommu.c'))
|
||||
|
||||
i386_ss.add(when: 'CONFIG_ACPI', if_true: files('acpi-common.c'))
|
||||
i386_ss.add(when: 'CONFIG_ACPI_HW_REDUCED', if_true: files('generic_event_device_x86.c'))
|
||||
i386_ss.add(when: 'CONFIG_PC', if_true: files(
|
||||
'pc.c',
|
||||
'pc_sysfw.c',
|
||||
|
@ -26,6 +26,8 @@
|
||||
#include "sysemu/cpus.h"
|
||||
#include "sysemu/numa.h"
|
||||
#include "sysemu/reset.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "acpi-microvm.h"
|
||||
|
||||
#include "hw/loader.h"
|
||||
#include "hw/irq.h"
|
||||
@ -37,17 +39,21 @@
|
||||
#include "hw/timer/i8254.h"
|
||||
#include "hw/rtc/mc146818rtc.h"
|
||||
#include "hw/char/serial.h"
|
||||
#include "hw/display/ramfb.h"
|
||||
#include "hw/i386/topology.h"
|
||||
#include "hw/i386/e820_memory_layout.h"
|
||||
#include "hw/i386/fw_cfg.h"
|
||||
#include "hw/virtio/virtio-mmio.h"
|
||||
#include "hw/acpi/acpi.h"
|
||||
#include "hw/acpi/generic_event_device.h"
|
||||
|
||||
#include "cpu.h"
|
||||
#include "elf.h"
|
||||
#include "kvm_i386.h"
|
||||
#include "hw/xen/start_info.h"
|
||||
|
||||
#define MICROVM_BIOS_FILENAME "bios-microvm.bin"
|
||||
#define MICROVM_QBOOT_FILENAME "qboot.rom"
|
||||
#define MICROVM_BIOS_FILENAME "bios-microvm.bin"
|
||||
|
||||
static void microvm_set_rtc(MicrovmMachineState *mms, ISADevice *s)
|
||||
{
|
||||
@ -121,13 +127,25 @@ static void microvm_devices_init(MicrovmMachineState *mms)
|
||||
|
||||
kvmclock_create();
|
||||
|
||||
mms->virtio_irq_base = x86_machine_is_acpi_enabled(x86ms) ? 16 : 5;
|
||||
for (i = 0; i < VIRTIO_NUM_TRANSPORTS; i++) {
|
||||
sysbus_create_simple("virtio-mmio",
|
||||
VIRTIO_MMIO_BASE + i * 512,
|
||||
x86ms->gsi[VIRTIO_IRQ_BASE + i]);
|
||||
x86ms->gsi[mms->virtio_irq_base + i]);
|
||||
}
|
||||
|
||||
/* Optional and legacy devices */
|
||||
if (x86_machine_is_acpi_enabled(x86ms)) {
|
||||
DeviceState *dev = qdev_new(TYPE_ACPI_GED_X86);
|
||||
qdev_prop_set_uint32(dev, "ged-event", ACPI_GED_PWR_DOWN_EVT);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, GED_MMIO_BASE);
|
||||
/* sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, GED_MMIO_BASE_MEMHP); */
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, GED_MMIO_BASE_REGS);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
|
||||
x86ms->gsi[GED_MMIO_IRQ]);
|
||||
sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
x86ms->acpi_dev = HOTPLUG_HANDLER(dev);
|
||||
}
|
||||
|
||||
if (mms->pic == ON_OFF_AUTO_ON || mms->pic == ON_OFF_AUTO_AUTO) {
|
||||
qemu_irq *i8259;
|
||||
@ -158,7 +176,9 @@ static void microvm_devices_init(MicrovmMachineState *mms)
|
||||
}
|
||||
|
||||
if (bios_name == NULL) {
|
||||
bios_name = MICROVM_BIOS_FILENAME;
|
||||
bios_name = x86_machine_is_acpi_enabled(x86ms)
|
||||
? MICROVM_BIOS_FILENAME
|
||||
: MICROVM_QBOOT_FILENAME;
|
||||
}
|
||||
x86_bios_rom_init(get_system_memory(), true);
|
||||
}
|
||||
@ -227,7 +247,7 @@ static void microvm_memory_init(MicrovmMachineState *mms)
|
||||
x86ms->ioapic_as = &address_space_memory;
|
||||
}
|
||||
|
||||
static gchar *microvm_get_mmio_cmdline(gchar *name)
|
||||
static gchar *microvm_get_mmio_cmdline(gchar *name, uint32_t virtio_irq_base)
|
||||
{
|
||||
gchar *cmdline;
|
||||
gchar *separator;
|
||||
@ -247,7 +267,7 @@ static gchar *microvm_get_mmio_cmdline(gchar *name)
|
||||
ret = g_snprintf(cmdline, VIRTIO_CMDLINE_MAXLEN,
|
||||
" virtio_mmio.device=512@0x%lx:%ld",
|
||||
VIRTIO_MMIO_BASE + index * 512,
|
||||
VIRTIO_IRQ_BASE + index);
|
||||
virtio_irq_base + index);
|
||||
if (ret < 0 || ret >= VIRTIO_CMDLINE_MAXLEN) {
|
||||
g_free(cmdline);
|
||||
return NULL;
|
||||
@ -259,6 +279,7 @@ static gchar *microvm_get_mmio_cmdline(gchar *name)
|
||||
static void microvm_fix_kernel_cmdline(MachineState *machine)
|
||||
{
|
||||
X86MachineState *x86ms = X86_MACHINE(machine);
|
||||
MicrovmMachineState *mms = MICROVM_MACHINE(machine);
|
||||
BusState *bus;
|
||||
BusChild *kid;
|
||||
char *cmdline;
|
||||
@ -282,7 +303,8 @@ static void microvm_fix_kernel_cmdline(MachineState *machine)
|
||||
BusState *mmio_bus = &mmio_virtio_bus->parent_obj;
|
||||
|
||||
if (!QTAILQ_EMPTY(&mmio_bus->children)) {
|
||||
gchar *mmio_cmdline = microvm_get_mmio_cmdline(mmio_bus->name);
|
||||
gchar *mmio_cmdline = microvm_get_mmio_cmdline
|
||||
(mmio_bus->name, mms->virtio_irq_base);
|
||||
if (mmio_cmdline) {
|
||||
char *newcmd = g_strjoin(NULL, cmdline, mmio_cmdline, NULL);
|
||||
g_free(mmio_cmdline);
|
||||
@ -299,6 +321,39 @@ static void microvm_fix_kernel_cmdline(MachineState *machine)
|
||||
g_free(cmdline);
|
||||
}
|
||||
|
||||
static void microvm_device_pre_plug_cb(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
x86_cpu_pre_plug(hotplug_dev, dev, errp);
|
||||
}
|
||||
|
||||
static void microvm_device_plug_cb(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
x86_cpu_plug(hotplug_dev, dev, errp);
|
||||
}
|
||||
|
||||
static void microvm_device_unplug_request_cb(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
error_setg(errp, "unplug not supported by microvm");
|
||||
}
|
||||
|
||||
static void microvm_device_unplug_cb(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
error_setg(errp, "unplug not supported by microvm");
|
||||
}
|
||||
|
||||
static HotplugHandler *microvm_get_hotplug_handler(MachineState *machine,
|
||||
DeviceState *dev)
|
||||
{
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
|
||||
return HOTPLUG_HANDLER(machine);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void microvm_machine_state_init(MachineState *machine)
|
||||
{
|
||||
MicrovmMachineState *mms = MICROVM_MACHINE(machine);
|
||||
@ -322,7 +377,8 @@ static void microvm_machine_reset(MachineState *machine)
|
||||
CPUState *cs;
|
||||
X86CPU *cpu;
|
||||
|
||||
if (machine->kernel_filename != NULL &&
|
||||
if (!x86_machine_is_acpi_enabled(X86_MACHINE(machine)) &&
|
||||
machine->kernel_filename != NULL &&
|
||||
mms->auto_kernel_cmdline && !mms->kernel_cmdline_fixed) {
|
||||
microvm_fix_kernel_cmdline(machine);
|
||||
mms->kernel_cmdline_fixed = true;
|
||||
@ -435,6 +491,28 @@ static void microvm_machine_set_auto_kernel_cmdline(Object *obj, bool value,
|
||||
mms->auto_kernel_cmdline = value;
|
||||
}
|
||||
|
||||
static void microvm_machine_done(Notifier *notifier, void *data)
|
||||
{
|
||||
MicrovmMachineState *mms = container_of(notifier, MicrovmMachineState,
|
||||
machine_done);
|
||||
|
||||
acpi_setup_microvm(mms);
|
||||
}
|
||||
|
||||
static void microvm_powerdown_req(Notifier *notifier, void *data)
|
||||
{
|
||||
MicrovmMachineState *mms = container_of(notifier, MicrovmMachineState,
|
||||
powerdown_req);
|
||||
X86MachineState *x86ms = X86_MACHINE(mms);
|
||||
|
||||
if (x86ms->acpi_dev) {
|
||||
Object *obj = OBJECT(x86ms->acpi_dev);
|
||||
AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(obj);
|
||||
adevc->send_event(ACPI_DEVICE_IF(x86ms->acpi_dev),
|
||||
ACPI_POWER_DOWN_STATUS);
|
||||
}
|
||||
}
|
||||
|
||||
static void microvm_machine_initfn(Object *obj)
|
||||
{
|
||||
MicrovmMachineState *mms = MICROVM_MACHINE(obj);
|
||||
@ -449,11 +527,17 @@ static void microvm_machine_initfn(Object *obj)
|
||||
|
||||
/* State */
|
||||
mms->kernel_cmdline_fixed = false;
|
||||
|
||||
mms->machine_done.notify = microvm_machine_done;
|
||||
qemu_add_machine_init_done_notifier(&mms->machine_done);
|
||||
mms->powerdown_req.notify = microvm_powerdown_req;
|
||||
qemu_register_powerdown_notifier(&mms->powerdown_req);
|
||||
}
|
||||
|
||||
static void microvm_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
|
||||
|
||||
mc->init = microvm_machine_state_init;
|
||||
|
||||
@ -475,6 +559,13 @@ static void microvm_class_init(ObjectClass *oc, void *data)
|
||||
/* Machine class handlers */
|
||||
mc->reset = microvm_machine_reset;
|
||||
|
||||
/* hotplug (for cpu coldplug) */
|
||||
mc->get_hotplug_handler = microvm_get_hotplug_handler;
|
||||
hc->pre_plug = microvm_device_pre_plug_cb;
|
||||
hc->plug = microvm_device_plug_cb;
|
||||
hc->unplug_request = microvm_device_unplug_request_cb;
|
||||
hc->unplug = microvm_device_unplug_cb;
|
||||
|
||||
object_class_property_add(oc, MICROVM_MACHINE_PIC, "OnOffAuto",
|
||||
microvm_machine_get_pic,
|
||||
microvm_machine_set_pic,
|
||||
@ -514,6 +605,8 @@ static void microvm_class_init(ObjectClass *oc, void *data)
|
||||
object_class_property_set_description(oc,
|
||||
MICROVM_MACHINE_AUTO_KERNEL_CMDLINE,
|
||||
"Set off to disable adding virtio-mmio devices to the kernel cmdline");
|
||||
|
||||
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE);
|
||||
}
|
||||
|
||||
static const TypeInfo microvm_machine_info = {
|
||||
@ -524,6 +617,7 @@ static const TypeInfo microvm_machine_info = {
|
||||
.class_size = sizeof(MicrovmMachineClass),
|
||||
.class_init = microvm_class_init,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ TYPE_HOTPLUG_HANDLER },
|
||||
{ }
|
||||
},
|
||||
};
|
||||
|
297
hw/i386/pc.c
297
hw/i386/pc.c
@ -803,19 +803,6 @@ void pc_hot_add_cpu(MachineState *ms, const int64_t id, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
static void rtc_set_cpus_count(ISADevice *rtc, uint16_t cpus_count)
|
||||
{
|
||||
if (cpus_count > 0xff) {
|
||||
/* If the number of CPUs can't be represented in 8 bits, the
|
||||
* BIOS must use "FW_CFG_NB_CPUS". Set RTC field to 0 just
|
||||
* to make old BIOSes fail more predictably.
|
||||
*/
|
||||
rtc_set_memory(rtc, 0x5f, 0);
|
||||
} else {
|
||||
rtc_set_memory(rtc, 0x5f, cpus_count - 1);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void pc_machine_done(Notifier *notifier, void *data)
|
||||
{
|
||||
@ -825,7 +812,7 @@ void pc_machine_done(Notifier *notifier, void *data)
|
||||
PCIBus *bus = pcms->bus;
|
||||
|
||||
/* set the number of CPUs */
|
||||
rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus);
|
||||
x86_rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus);
|
||||
|
||||
if (bus) {
|
||||
int extra_hosts = 0;
|
||||
@ -1274,6 +1261,7 @@ static void pc_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||
Error **errp)
|
||||
{
|
||||
const PCMachineState *pcms = PC_MACHINE(hotplug_dev);
|
||||
const X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
|
||||
const PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
|
||||
const MachineState *ms = MACHINE(hotplug_dev);
|
||||
const bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
|
||||
@ -1285,7 +1273,7 @@ static void pc_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||
* but pcms->acpi_dev is still created. Check !acpi_enabled in
|
||||
* addition to cover this case.
|
||||
*/
|
||||
if (!pcms->acpi_dev || !x86_machine_is_acpi_enabled(X86_MACHINE(pcms))) {
|
||||
if (!x86ms->acpi_dev || !x86_machine_is_acpi_enabled(x86ms)) {
|
||||
error_setg(errp,
|
||||
"memory hotplug is not enabled: missing acpi device or acpi disabled");
|
||||
return;
|
||||
@ -1296,7 +1284,7 @@ static void pc_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||
return;
|
||||
}
|
||||
|
||||
hotplug_handler_pre_plug(pcms->acpi_dev, dev, &local_err);
|
||||
hotplug_handler_pre_plug(x86ms->acpi_dev, dev, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
@ -1311,6 +1299,7 @@ static void pc_memory_plug(HotplugHandler *hotplug_dev,
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
PCMachineState *pcms = PC_MACHINE(hotplug_dev);
|
||||
X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
|
||||
MachineState *ms = MACHINE(hotplug_dev);
|
||||
bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
|
||||
|
||||
@ -1323,7 +1312,7 @@ static void pc_memory_plug(HotplugHandler *hotplug_dev,
|
||||
nvdimm_plug(ms->nvdimms_state);
|
||||
}
|
||||
|
||||
hotplug_handler_plug(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &error_abort);
|
||||
hotplug_handler_plug(x86ms->acpi_dev, dev, &error_abort);
|
||||
out:
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
@ -1331,14 +1320,14 @@ out:
|
||||
static void pc_memory_unplug_request(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
PCMachineState *pcms = PC_MACHINE(hotplug_dev);
|
||||
X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
|
||||
|
||||
/*
|
||||
* When -no-acpi is used with Q35 machine type, no ACPI is built,
|
||||
* but pcms->acpi_dev is still created. Check !acpi_enabled in
|
||||
* addition to cover this case.
|
||||
*/
|
||||
if (!pcms->acpi_dev || !x86_machine_is_acpi_enabled(X86_MACHINE(pcms))) {
|
||||
if (!x86ms->acpi_dev || !x86_machine_is_acpi_enabled(x86ms)) {
|
||||
error_setg(errp,
|
||||
"memory hotplug is not enabled: missing acpi device or acpi disabled");
|
||||
return;
|
||||
@ -1349,7 +1338,7 @@ static void pc_memory_unplug_request(HotplugHandler *hotplug_dev,
|
||||
return;
|
||||
}
|
||||
|
||||
hotplug_handler_unplug_request(HOTPLUG_HANDLER(pcms->acpi_dev), dev,
|
||||
hotplug_handler_unplug_request(x86ms->acpi_dev, dev,
|
||||
errp);
|
||||
}
|
||||
|
||||
@ -1357,9 +1346,10 @@ static void pc_memory_unplug(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
PCMachineState *pcms = PC_MACHINE(hotplug_dev);
|
||||
X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
|
||||
Error *local_err = NULL;
|
||||
|
||||
hotplug_handler_unplug(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &local_err);
|
||||
hotplug_handler_unplug(x86ms->acpi_dev, dev, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
@ -1370,263 +1360,6 @@ static void pc_memory_unplug(HotplugHandler *hotplug_dev,
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
static int pc_apic_cmp(const void *a, const void *b)
|
||||
{
|
||||
CPUArchId *apic_a = (CPUArchId *)a;
|
||||
CPUArchId *apic_b = (CPUArchId *)b;
|
||||
|
||||
return apic_a->arch_id - apic_b->arch_id;
|
||||
}
|
||||
|
||||
/* returns pointer to CPUArchId descriptor that matches CPU's apic_id
|
||||
* in ms->possible_cpus->cpus, if ms->possible_cpus->cpus has no
|
||||
* entry corresponding to CPU's apic_id returns NULL.
|
||||
*/
|
||||
static CPUArchId *pc_find_cpu_slot(MachineState *ms, uint32_t id, int *idx)
|
||||
{
|
||||
CPUArchId apic_id, *found_cpu;
|
||||
|
||||
apic_id.arch_id = id;
|
||||
found_cpu = bsearch(&apic_id, ms->possible_cpus->cpus,
|
||||
ms->possible_cpus->len, sizeof(*ms->possible_cpus->cpus),
|
||||
pc_apic_cmp);
|
||||
if (found_cpu && idx) {
|
||||
*idx = found_cpu - ms->possible_cpus->cpus;
|
||||
}
|
||||
return found_cpu;
|
||||
}
|
||||
|
||||
static void pc_cpu_plug(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
CPUArchId *found_cpu;
|
||||
Error *local_err = NULL;
|
||||
X86CPU *cpu = X86_CPU(dev);
|
||||
PCMachineState *pcms = PC_MACHINE(hotplug_dev);
|
||||
X86MachineState *x86ms = X86_MACHINE(pcms);
|
||||
|
||||
if (pcms->acpi_dev) {
|
||||
hotplug_handler_plug(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* increment the number of CPUs */
|
||||
x86ms->boot_cpus++;
|
||||
if (x86ms->rtc) {
|
||||
rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus);
|
||||
}
|
||||
if (x86ms->fw_cfg) {
|
||||
fw_cfg_modify_i16(x86ms->fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus);
|
||||
}
|
||||
|
||||
found_cpu = pc_find_cpu_slot(MACHINE(pcms), cpu->apic_id, NULL);
|
||||
found_cpu->cpu = OBJECT(dev);
|
||||
out:
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
static void pc_cpu_unplug_request_cb(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
int idx = -1;
|
||||
X86CPU *cpu = X86_CPU(dev);
|
||||
PCMachineState *pcms = PC_MACHINE(hotplug_dev);
|
||||
|
||||
if (!pcms->acpi_dev) {
|
||||
error_setg(errp, "CPU hot unplug not supported without ACPI");
|
||||
return;
|
||||
}
|
||||
|
||||
pc_find_cpu_slot(MACHINE(pcms), cpu->apic_id, &idx);
|
||||
assert(idx != -1);
|
||||
if (idx == 0) {
|
||||
error_setg(errp, "Boot CPU is unpluggable");
|
||||
return;
|
||||
}
|
||||
|
||||
hotplug_handler_unplug_request(HOTPLUG_HANDLER(pcms->acpi_dev), dev,
|
||||
errp);
|
||||
}
|
||||
|
||||
static void pc_cpu_unplug_cb(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
CPUArchId *found_cpu;
|
||||
Error *local_err = NULL;
|
||||
X86CPU *cpu = X86_CPU(dev);
|
||||
PCMachineState *pcms = PC_MACHINE(hotplug_dev);
|
||||
X86MachineState *x86ms = X86_MACHINE(pcms);
|
||||
|
||||
hotplug_handler_unplug(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
found_cpu = pc_find_cpu_slot(MACHINE(pcms), cpu->apic_id, NULL);
|
||||
found_cpu->cpu = NULL;
|
||||
qdev_unrealize(dev);
|
||||
|
||||
/* decrement the number of CPUs */
|
||||
x86ms->boot_cpus--;
|
||||
/* Update the number of CPUs in CMOS */
|
||||
rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus);
|
||||
fw_cfg_modify_i16(x86ms->fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus);
|
||||
out:
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
static void pc_cpu_pre_plug(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
int idx;
|
||||
CPUState *cs;
|
||||
CPUArchId *cpu_slot;
|
||||
X86CPUTopoIDs topo_ids;
|
||||
X86CPU *cpu = X86_CPU(dev);
|
||||
CPUX86State *env = &cpu->env;
|
||||
MachineState *ms = MACHINE(hotplug_dev);
|
||||
PCMachineState *pcms = PC_MACHINE(hotplug_dev);
|
||||
X86MachineState *x86ms = X86_MACHINE(pcms);
|
||||
unsigned int smp_cores = ms->smp.cores;
|
||||
unsigned int smp_threads = ms->smp.threads;
|
||||
X86CPUTopoInfo topo_info;
|
||||
|
||||
if(!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) {
|
||||
error_setg(errp, "Invalid CPU type, expected cpu type: '%s'",
|
||||
ms->cpu_type);
|
||||
return;
|
||||
}
|
||||
|
||||
init_topo_info(&topo_info, x86ms);
|
||||
|
||||
env->nr_dies = x86ms->smp_dies;
|
||||
|
||||
/*
|
||||
* If APIC ID is not set,
|
||||
* set it based on socket/die/core/thread properties.
|
||||
*/
|
||||
if (cpu->apic_id == UNASSIGNED_APIC_ID) {
|
||||
int max_socket = (ms->smp.max_cpus - 1) /
|
||||
smp_threads / smp_cores / x86ms->smp_dies;
|
||||
|
||||
/*
|
||||
* die-id was optional in QEMU 4.0 and older, so keep it optional
|
||||
* if there's only one die per socket.
|
||||
*/
|
||||
if (cpu->die_id < 0 && x86ms->smp_dies == 1) {
|
||||
cpu->die_id = 0;
|
||||
}
|
||||
|
||||
if (cpu->socket_id < 0) {
|
||||
error_setg(errp, "CPU socket-id is not set");
|
||||
return;
|
||||
} else if (cpu->socket_id > max_socket) {
|
||||
error_setg(errp, "Invalid CPU socket-id: %u must be in range 0:%u",
|
||||
cpu->socket_id, max_socket);
|
||||
return;
|
||||
}
|
||||
if (cpu->die_id < 0) {
|
||||
error_setg(errp, "CPU die-id is not set");
|
||||
return;
|
||||
} else if (cpu->die_id > x86ms->smp_dies - 1) {
|
||||
error_setg(errp, "Invalid CPU die-id: %u must be in range 0:%u",
|
||||
cpu->die_id, x86ms->smp_dies - 1);
|
||||
return;
|
||||
}
|
||||
if (cpu->core_id < 0) {
|
||||
error_setg(errp, "CPU core-id is not set");
|
||||
return;
|
||||
} else if (cpu->core_id > (smp_cores - 1)) {
|
||||
error_setg(errp, "Invalid CPU core-id: %u must be in range 0:%u",
|
||||
cpu->core_id, smp_cores - 1);
|
||||
return;
|
||||
}
|
||||
if (cpu->thread_id < 0) {
|
||||
error_setg(errp, "CPU thread-id is not set");
|
||||
return;
|
||||
} else if (cpu->thread_id > (smp_threads - 1)) {
|
||||
error_setg(errp, "Invalid CPU thread-id: %u must be in range 0:%u",
|
||||
cpu->thread_id, smp_threads - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
topo_ids.pkg_id = cpu->socket_id;
|
||||
topo_ids.die_id = cpu->die_id;
|
||||
topo_ids.core_id = cpu->core_id;
|
||||
topo_ids.smt_id = cpu->thread_id;
|
||||
cpu->apic_id = x86_apicid_from_topo_ids(&topo_info, &topo_ids);
|
||||
}
|
||||
|
||||
cpu_slot = pc_find_cpu_slot(MACHINE(pcms), cpu->apic_id, &idx);
|
||||
if (!cpu_slot) {
|
||||
MachineState *ms = MACHINE(pcms);
|
||||
|
||||
x86_topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids);
|
||||
error_setg(errp,
|
||||
"Invalid CPU [socket: %u, die: %u, core: %u, thread: %u] with"
|
||||
" APIC ID %" PRIu32 ", valid index range 0:%d",
|
||||
topo_ids.pkg_id, topo_ids.die_id, topo_ids.core_id, topo_ids.smt_id,
|
||||
cpu->apic_id, ms->possible_cpus->len - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cpu_slot->cpu) {
|
||||
error_setg(errp, "CPU[%d] with APIC ID %" PRIu32 " exists",
|
||||
idx, cpu->apic_id);
|
||||
return;
|
||||
}
|
||||
|
||||
/* if 'address' properties socket-id/core-id/thread-id are not set, set them
|
||||
* so that machine_query_hotpluggable_cpus would show correct values
|
||||
*/
|
||||
/* TODO: move socket_id/core_id/thread_id checks into x86_cpu_realizefn()
|
||||
* once -smp refactoring is complete and there will be CPU private
|
||||
* CPUState::nr_cores and CPUState::nr_threads fields instead of globals */
|
||||
x86_topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids);
|
||||
if (cpu->socket_id != -1 && cpu->socket_id != topo_ids.pkg_id) {
|
||||
error_setg(errp, "property socket-id: %u doesn't match set apic-id:"
|
||||
" 0x%x (socket-id: %u)", cpu->socket_id, cpu->apic_id,
|
||||
topo_ids.pkg_id);
|
||||
return;
|
||||
}
|
||||
cpu->socket_id = topo_ids.pkg_id;
|
||||
|
||||
if (cpu->die_id != -1 && cpu->die_id != topo_ids.die_id) {
|
||||
error_setg(errp, "property die-id: %u doesn't match set apic-id:"
|
||||
" 0x%x (die-id: %u)", cpu->die_id, cpu->apic_id, topo_ids.die_id);
|
||||
return;
|
||||
}
|
||||
cpu->die_id = topo_ids.die_id;
|
||||
|
||||
if (cpu->core_id != -1 && cpu->core_id != topo_ids.core_id) {
|
||||
error_setg(errp, "property core-id: %u doesn't match set apic-id:"
|
||||
" 0x%x (core-id: %u)", cpu->core_id, cpu->apic_id,
|
||||
topo_ids.core_id);
|
||||
return;
|
||||
}
|
||||
cpu->core_id = topo_ids.core_id;
|
||||
|
||||
if (cpu->thread_id != -1 && cpu->thread_id != topo_ids.smt_id) {
|
||||
error_setg(errp, "property thread-id: %u doesn't match set apic-id:"
|
||||
" 0x%x (thread-id: %u)", cpu->thread_id, cpu->apic_id,
|
||||
topo_ids.smt_id);
|
||||
return;
|
||||
}
|
||||
cpu->thread_id = topo_ids.smt_id;
|
||||
|
||||
if (hyperv_feat_enabled(cpu, HYPERV_FEAT_VPINDEX) &&
|
||||
!kvm_hv_vpindex_settable()) {
|
||||
error_setg(errp, "kernel doesn't allow setting HyperV VP_INDEX");
|
||||
return;
|
||||
}
|
||||
|
||||
cs = CPU(cpu);
|
||||
cs->cpu_index = idx;
|
||||
|
||||
numa_cpu_pre_plug(cpu_slot, dev, errp);
|
||||
}
|
||||
|
||||
static void pc_virtio_md_pci_pre_plug(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
@ -1695,7 +1428,7 @@ static void pc_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
|
||||
pc_memory_pre_plug(hotplug_dev, dev, errp);
|
||||
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
|
||||
pc_cpu_pre_plug(hotplug_dev, dev, errp);
|
||||
x86_cpu_pre_plug(hotplug_dev, dev, errp);
|
||||
} else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI) ||
|
||||
object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MEM_PCI)) {
|
||||
pc_virtio_md_pci_pre_plug(hotplug_dev, dev, errp);
|
||||
@ -1708,7 +1441,7 @@ static void pc_machine_device_plug_cb(HotplugHandler *hotplug_dev,
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
|
||||
pc_memory_plug(hotplug_dev, dev, errp);
|
||||
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
|
||||
pc_cpu_plug(hotplug_dev, dev, errp);
|
||||
x86_cpu_plug(hotplug_dev, dev, errp);
|
||||
} else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI) ||
|
||||
object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MEM_PCI)) {
|
||||
pc_virtio_md_pci_plug(hotplug_dev, dev, errp);
|
||||
@ -1721,7 +1454,7 @@ static void pc_machine_device_unplug_request_cb(HotplugHandler *hotplug_dev,
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
|
||||
pc_memory_unplug_request(hotplug_dev, dev, errp);
|
||||
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
|
||||
pc_cpu_unplug_request_cb(hotplug_dev, dev, errp);
|
||||
x86_cpu_unplug_request_cb(hotplug_dev, dev, errp);
|
||||
} else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI) ||
|
||||
object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MEM_PCI)) {
|
||||
pc_virtio_md_pci_unplug_request(hotplug_dev, dev, errp);
|
||||
@ -1737,7 +1470,7 @@ static void pc_machine_device_unplug_cb(HotplugHandler *hotplug_dev,
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
|
||||
pc_memory_unplug(hotplug_dev, dev, errp);
|
||||
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
|
||||
pc_cpu_unplug_cb(hotplug_dev, dev, errp);
|
||||
x86_cpu_unplug_cb(hotplug_dev, dev, errp);
|
||||
} else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_PMEM_PCI) ||
|
||||
object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MEM_PCI)) {
|
||||
pc_virtio_md_pci_unplug(hotplug_dev, dev, errp);
|
||||
|
@ -293,7 +293,7 @@ static void pc_init1(MachineState *machine,
|
||||
|
||||
object_property_add_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP,
|
||||
TYPE_HOTPLUG_HANDLER,
|
||||
(Object **)&pcms->acpi_dev,
|
||||
(Object **)&x86ms->acpi_dev,
|
||||
object_property_allow_set_link,
|
||||
OBJ_PROP_LINK_STRONG);
|
||||
object_property_set_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP,
|
||||
|
@ -240,7 +240,7 @@ static void pc_q35_init(MachineState *machine)
|
||||
|
||||
object_property_add_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP,
|
||||
TYPE_HOTPLUG_HANDLER,
|
||||
(Object **)&pcms->acpi_dev,
|
||||
(Object **)&x86ms->acpi_dev,
|
||||
object_property_allow_set_link,
|
||||
OBJ_PROP_LINK_STRONG);
|
||||
object_property_set_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP,
|
||||
|
275
hw/i386/x86.c
275
hw/i386/x86.c
@ -41,6 +41,7 @@
|
||||
#include "hw/i386/topology.h"
|
||||
#include "hw/i386/fw_cfg.h"
|
||||
#include "hw/intc/i8259.h"
|
||||
#include "hw/rtc/mc146818rtc.h"
|
||||
|
||||
#include "hw/acpi/cpu_hotplug.h"
|
||||
#include "hw/irq.h"
|
||||
@ -137,6 +138,276 @@ void x86_cpus_init(X86MachineState *x86ms, int default_cpu_version)
|
||||
}
|
||||
}
|
||||
|
||||
void x86_rtc_set_cpus_count(ISADevice *rtc, uint16_t cpus_count)
|
||||
{
|
||||
if (cpus_count > 0xff) {
|
||||
/*
|
||||
* If the number of CPUs can't be represented in 8 bits, the
|
||||
* BIOS must use "FW_CFG_NB_CPUS". Set RTC field to 0 just
|
||||
* to make old BIOSes fail more predictably.
|
||||
*/
|
||||
rtc_set_memory(rtc, 0x5f, 0);
|
||||
} else {
|
||||
rtc_set_memory(rtc, 0x5f, cpus_count - 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int x86_apic_cmp(const void *a, const void *b)
|
||||
{
|
||||
CPUArchId *apic_a = (CPUArchId *)a;
|
||||
CPUArchId *apic_b = (CPUArchId *)b;
|
||||
|
||||
return apic_a->arch_id - apic_b->arch_id;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns pointer to CPUArchId descriptor that matches CPU's apic_id
|
||||
* in ms->possible_cpus->cpus, if ms->possible_cpus->cpus has no
|
||||
* entry corresponding to CPU's apic_id returns NULL.
|
||||
*/
|
||||
CPUArchId *x86_find_cpu_slot(MachineState *ms, uint32_t id, int *idx)
|
||||
{
|
||||
CPUArchId apic_id, *found_cpu;
|
||||
|
||||
apic_id.arch_id = id;
|
||||
found_cpu = bsearch(&apic_id, ms->possible_cpus->cpus,
|
||||
ms->possible_cpus->len, sizeof(*ms->possible_cpus->cpus),
|
||||
x86_apic_cmp);
|
||||
if (found_cpu && idx) {
|
||||
*idx = found_cpu - ms->possible_cpus->cpus;
|
||||
}
|
||||
return found_cpu;
|
||||
}
|
||||
|
||||
void x86_cpu_plug(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
CPUArchId *found_cpu;
|
||||
Error *local_err = NULL;
|
||||
X86CPU *cpu = X86_CPU(dev);
|
||||
X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
|
||||
|
||||
if (x86ms->acpi_dev) {
|
||||
hotplug_handler_plug(x86ms->acpi_dev, dev, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* increment the number of CPUs */
|
||||
x86ms->boot_cpus++;
|
||||
if (x86ms->rtc) {
|
||||
x86_rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus);
|
||||
}
|
||||
if (x86ms->fw_cfg) {
|
||||
fw_cfg_modify_i16(x86ms->fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus);
|
||||
}
|
||||
|
||||
found_cpu = x86_find_cpu_slot(MACHINE(x86ms), cpu->apic_id, NULL);
|
||||
found_cpu->cpu = OBJECT(dev);
|
||||
out:
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
void x86_cpu_unplug_request_cb(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
int idx = -1;
|
||||
X86CPU *cpu = X86_CPU(dev);
|
||||
X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
|
||||
|
||||
if (!x86ms->acpi_dev) {
|
||||
error_setg(errp, "CPU hot unplug not supported without ACPI");
|
||||
return;
|
||||
}
|
||||
|
||||
x86_find_cpu_slot(MACHINE(x86ms), cpu->apic_id, &idx);
|
||||
assert(idx != -1);
|
||||
if (idx == 0) {
|
||||
error_setg(errp, "Boot CPU is unpluggable");
|
||||
return;
|
||||
}
|
||||
|
||||
hotplug_handler_unplug_request(x86ms->acpi_dev, dev,
|
||||
errp);
|
||||
}
|
||||
|
||||
void x86_cpu_unplug_cb(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
CPUArchId *found_cpu;
|
||||
Error *local_err = NULL;
|
||||
X86CPU *cpu = X86_CPU(dev);
|
||||
X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
|
||||
|
||||
hotplug_handler_unplug(x86ms->acpi_dev, dev, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
found_cpu = x86_find_cpu_slot(MACHINE(x86ms), cpu->apic_id, NULL);
|
||||
found_cpu->cpu = NULL;
|
||||
qdev_unrealize(dev);
|
||||
|
||||
/* decrement the number of CPUs */
|
||||
x86ms->boot_cpus--;
|
||||
/* Update the number of CPUs in CMOS */
|
||||
x86_rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus);
|
||||
fw_cfg_modify_i16(x86ms->fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus);
|
||||
out:
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
void x86_cpu_pre_plug(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
int idx;
|
||||
CPUState *cs;
|
||||
CPUArchId *cpu_slot;
|
||||
X86CPUTopoIDs topo_ids;
|
||||
X86CPU *cpu = X86_CPU(dev);
|
||||
CPUX86State *env = &cpu->env;
|
||||
MachineState *ms = MACHINE(hotplug_dev);
|
||||
X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
|
||||
unsigned int smp_cores = ms->smp.cores;
|
||||
unsigned int smp_threads = ms->smp.threads;
|
||||
X86CPUTopoInfo topo_info;
|
||||
|
||||
if (!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) {
|
||||
error_setg(errp, "Invalid CPU type, expected cpu type: '%s'",
|
||||
ms->cpu_type);
|
||||
return;
|
||||
}
|
||||
|
||||
init_topo_info(&topo_info, x86ms);
|
||||
|
||||
env->nr_dies = x86ms->smp_dies;
|
||||
|
||||
/*
|
||||
* If APIC ID is not set,
|
||||
* set it based on socket/die/core/thread properties.
|
||||
*/
|
||||
if (cpu->apic_id == UNASSIGNED_APIC_ID) {
|
||||
int max_socket = (ms->smp.max_cpus - 1) /
|
||||
smp_threads / smp_cores / x86ms->smp_dies;
|
||||
|
||||
/*
|
||||
* die-id was optional in QEMU 4.0 and older, so keep it optional
|
||||
* if there's only one die per socket.
|
||||
*/
|
||||
if (cpu->die_id < 0 && x86ms->smp_dies == 1) {
|
||||
cpu->die_id = 0;
|
||||
}
|
||||
|
||||
if (cpu->socket_id < 0) {
|
||||
error_setg(errp, "CPU socket-id is not set");
|
||||
return;
|
||||
} else if (cpu->socket_id > max_socket) {
|
||||
error_setg(errp, "Invalid CPU socket-id: %u must be in range 0:%u",
|
||||
cpu->socket_id, max_socket);
|
||||
return;
|
||||
}
|
||||
if (cpu->die_id < 0) {
|
||||
error_setg(errp, "CPU die-id is not set");
|
||||
return;
|
||||
} else if (cpu->die_id > x86ms->smp_dies - 1) {
|
||||
error_setg(errp, "Invalid CPU die-id: %u must be in range 0:%u",
|
||||
cpu->die_id, x86ms->smp_dies - 1);
|
||||
return;
|
||||
}
|
||||
if (cpu->core_id < 0) {
|
||||
error_setg(errp, "CPU core-id is not set");
|
||||
return;
|
||||
} else if (cpu->core_id > (smp_cores - 1)) {
|
||||
error_setg(errp, "Invalid CPU core-id: %u must be in range 0:%u",
|
||||
cpu->core_id, smp_cores - 1);
|
||||
return;
|
||||
}
|
||||
if (cpu->thread_id < 0) {
|
||||
error_setg(errp, "CPU thread-id is not set");
|
||||
return;
|
||||
} else if (cpu->thread_id > (smp_threads - 1)) {
|
||||
error_setg(errp, "Invalid CPU thread-id: %u must be in range 0:%u",
|
||||
cpu->thread_id, smp_threads - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
topo_ids.pkg_id = cpu->socket_id;
|
||||
topo_ids.die_id = cpu->die_id;
|
||||
topo_ids.core_id = cpu->core_id;
|
||||
topo_ids.smt_id = cpu->thread_id;
|
||||
cpu->apic_id = x86_apicid_from_topo_ids(&topo_info, &topo_ids);
|
||||
}
|
||||
|
||||
cpu_slot = x86_find_cpu_slot(MACHINE(x86ms), cpu->apic_id, &idx);
|
||||
if (!cpu_slot) {
|
||||
MachineState *ms = MACHINE(x86ms);
|
||||
|
||||
x86_topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids);
|
||||
error_setg(errp,
|
||||
"Invalid CPU [socket: %u, die: %u, core: %u, thread: %u] with"
|
||||
" APIC ID %" PRIu32 ", valid index range 0:%d",
|
||||
topo_ids.pkg_id, topo_ids.die_id, topo_ids.core_id, topo_ids.smt_id,
|
||||
cpu->apic_id, ms->possible_cpus->len - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cpu_slot->cpu) {
|
||||
error_setg(errp, "CPU[%d] with APIC ID %" PRIu32 " exists",
|
||||
idx, cpu->apic_id);
|
||||
return;
|
||||
}
|
||||
|
||||
/* if 'address' properties socket-id/core-id/thread-id are not set, set them
|
||||
* so that machine_query_hotpluggable_cpus would show correct values
|
||||
*/
|
||||
/* TODO: move socket_id/core_id/thread_id checks into x86_cpu_realizefn()
|
||||
* once -smp refactoring is complete and there will be CPU private
|
||||
* CPUState::nr_cores and CPUState::nr_threads fields instead of globals */
|
||||
x86_topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids);
|
||||
if (cpu->socket_id != -1 && cpu->socket_id != topo_ids.pkg_id) {
|
||||
error_setg(errp, "property socket-id: %u doesn't match set apic-id:"
|
||||
" 0x%x (socket-id: %u)", cpu->socket_id, cpu->apic_id,
|
||||
topo_ids.pkg_id);
|
||||
return;
|
||||
}
|
||||
cpu->socket_id = topo_ids.pkg_id;
|
||||
|
||||
if (cpu->die_id != -1 && cpu->die_id != topo_ids.die_id) {
|
||||
error_setg(errp, "property die-id: %u doesn't match set apic-id:"
|
||||
" 0x%x (die-id: %u)", cpu->die_id, cpu->apic_id, topo_ids.die_id);
|
||||
return;
|
||||
}
|
||||
cpu->die_id = topo_ids.die_id;
|
||||
|
||||
if (cpu->core_id != -1 && cpu->core_id != topo_ids.core_id) {
|
||||
error_setg(errp, "property core-id: %u doesn't match set apic-id:"
|
||||
" 0x%x (core-id: %u)", cpu->core_id, cpu->apic_id,
|
||||
topo_ids.core_id);
|
||||
return;
|
||||
}
|
||||
cpu->core_id = topo_ids.core_id;
|
||||
|
||||
if (cpu->thread_id != -1 && cpu->thread_id != topo_ids.smt_id) {
|
||||
error_setg(errp, "property thread-id: %u doesn't match set apic-id:"
|
||||
" 0x%x (thread-id: %u)", cpu->thread_id, cpu->apic_id,
|
||||
topo_ids.smt_id);
|
||||
return;
|
||||
}
|
||||
cpu->thread_id = topo_ids.smt_id;
|
||||
|
||||
if (hyperv_feat_enabled(cpu, HYPERV_FEAT_VPINDEX) &&
|
||||
!kvm_hv_vpindex_settable()) {
|
||||
error_setg(errp, "kernel doesn't allow setting HyperV VP_INDEX");
|
||||
return;
|
||||
}
|
||||
|
||||
cs = CPU(cpu);
|
||||
cs->cpu_index = idx;
|
||||
|
||||
numa_cpu_pre_plug(cpu_slot, dev, errp);
|
||||
}
|
||||
|
||||
CpuInstanceProperties
|
||||
x86_cpu_index_to_props(MachineState *ms, unsigned cpu_index)
|
||||
{
|
||||
@ -821,7 +1092,7 @@ void x86_bios_rom_init(MemoryRegion *rom_memory, bool isapc_ram_fw)
|
||||
bios);
|
||||
}
|
||||
|
||||
bool x86_machine_is_smm_enabled(X86MachineState *x86ms)
|
||||
bool x86_machine_is_smm_enabled(const X86MachineState *x86ms)
|
||||
{
|
||||
bool smm_available = false;
|
||||
|
||||
@ -863,7 +1134,7 @@ static void x86_machine_set_smm(Object *obj, Visitor *v, const char *name,
|
||||
visit_type_OnOffAuto(v, name, &x86ms->smm, errp);
|
||||
}
|
||||
|
||||
bool x86_machine_is_acpi_enabled(X86MachineState *x86ms)
|
||||
bool x86_machine_is_acpi_enabled(const X86MachineState *x86ms)
|
||||
{
|
||||
if (x86ms->acpi == ON_OFF_AUTO_OFF) {
|
||||
return false;
|
||||
|
@ -71,9 +71,24 @@ typedef struct AcpiGedState AcpiGedState;
|
||||
DECLARE_INSTANCE_CHECKER(AcpiGedState, ACPI_GED,
|
||||
TYPE_ACPI_GED)
|
||||
|
||||
#define TYPE_ACPI_GED_X86 "acpi-ged-x86"
|
||||
#define ACPI_GED_X86(obj) \
|
||||
OBJECT_CHECK(AcpiGedX86State, (obj), TYPE_ACPI_GED_X86)
|
||||
|
||||
#define ACPI_GED_EVT_SEL_OFFSET 0x0
|
||||
#define ACPI_GED_EVT_SEL_LEN 0x4
|
||||
|
||||
#define ACPI_GED_REG_SLEEP_CTL 0x00
|
||||
#define ACPI_GED_REG_SLEEP_STS 0x01
|
||||
#define ACPI_GED_REG_RESET 0x02
|
||||
#define ACPI_GED_REG_COUNT 0x03
|
||||
|
||||
/* ACPI_GED_REG_RESET value for reset*/
|
||||
#define ACPI_GED_RESET_VALUE 0x42
|
||||
|
||||
/* ACPI_GED_REG_SLEEP_CTL.SLP_TYP value for S5 (aka poweroff) */
|
||||
#define ACPI_GED_SLP_TYP_S5 0x05
|
||||
|
||||
#define GED_DEVICE "GED"
|
||||
#define AML_GED_EVT_REG "EREG"
|
||||
#define AML_GED_EVT_SEL "ESEL"
|
||||
@ -89,6 +104,7 @@ DECLARE_INSTANCE_CHECKER(AcpiGedState, ACPI_GED,
|
||||
|
||||
typedef struct GEDState {
|
||||
MemoryRegion evt;
|
||||
MemoryRegion regs;
|
||||
uint32_t sel;
|
||||
} GEDState;
|
||||
|
||||
@ -104,5 +120,6 @@ struct AcpiGedState {
|
||||
|
||||
void build_ged_aml(Aml *table, const char* name, HotplugHandler *hotplug_dev,
|
||||
uint32_t ged_irq, AmlRegionSpace rs, hwaddr ged_base);
|
||||
void acpi_dsdt_add_power_button(Aml *scope);
|
||||
|
||||
#endif
|
||||
|
@ -24,14 +24,19 @@
|
||||
|
||||
#include "hw/boards.h"
|
||||
#include "hw/i386/x86.h"
|
||||
#include "hw/acpi/acpi_dev_interface.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
/* Platform virtio definitions */
|
||||
#define VIRTIO_MMIO_BASE 0xfeb00000
|
||||
#define VIRTIO_IRQ_BASE 5
|
||||
#define VIRTIO_NUM_TRANSPORTS 8
|
||||
#define VIRTIO_CMDLINE_MAXLEN 64
|
||||
|
||||
#define GED_MMIO_BASE 0xfea00000
|
||||
#define GED_MMIO_BASE_MEMHP (GED_MMIO_BASE + 0x100)
|
||||
#define GED_MMIO_BASE_REGS (GED_MMIO_BASE + 0x200)
|
||||
#define GED_MMIO_IRQ 9
|
||||
|
||||
/* Machine type options */
|
||||
#define MICROVM_MACHINE_PIT "pit"
|
||||
#define MICROVM_MACHINE_PIC "pic"
|
||||
@ -59,7 +64,10 @@ struct MicrovmMachineState {
|
||||
bool auto_kernel_cmdline;
|
||||
|
||||
/* Machine state */
|
||||
uint32_t virtio_irq_base;
|
||||
bool kernel_cmdline_fixed;
|
||||
Notifier machine_done;
|
||||
Notifier powerdown_req;
|
||||
};
|
||||
typedef struct MicrovmMachineState MicrovmMachineState;
|
||||
|
||||
|
@ -30,7 +30,6 @@ struct PCMachineState {
|
||||
Notifier machine_done;
|
||||
|
||||
/* Pointers to devices and objects: */
|
||||
HotplugHandler *acpi_dev;
|
||||
PCIBus *bus;
|
||||
I2CBus *smbus;
|
||||
PFlashCFI01 *flash[2];
|
||||
|
@ -52,6 +52,7 @@ struct X86MachineState {
|
||||
FWCfgState *fw_cfg;
|
||||
qemu_irq *gsi;
|
||||
GMappedFile *initrd_mapped_file;
|
||||
HotplugHandler *acpi_dev;
|
||||
|
||||
/* RAM information (sizes, addresses, configuration): */
|
||||
ram_addr_t below_4g_mem_size, above_4g_mem_size;
|
||||
@ -91,6 +92,16 @@ CpuInstanceProperties x86_cpu_index_to_props(MachineState *ms,
|
||||
unsigned cpu_index);
|
||||
int64_t x86_get_default_cpu_node_id(const MachineState *ms, int idx);
|
||||
const CPUArchIdList *x86_possible_cpu_arch_ids(MachineState *ms);
|
||||
CPUArchId *x86_find_cpu_slot(MachineState *ms, uint32_t id, int *idx);
|
||||
void x86_rtc_set_cpus_count(ISADevice *rtc, uint16_t cpus_count);
|
||||
void x86_cpu_pre_plug(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp);
|
||||
void x86_cpu_plug(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp);
|
||||
void x86_cpu_unplug_request_cb(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp);
|
||||
void x86_cpu_unplug_cb(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp);
|
||||
|
||||
void x86_bios_rom_init(MemoryRegion *rom_memory, bool isapc_ram_fw);
|
||||
|
||||
@ -100,8 +111,8 @@ void x86_load_linux(X86MachineState *x86ms,
|
||||
bool pvh_enabled,
|
||||
bool linuxboot_dma_enabled);
|
||||
|
||||
bool x86_machine_is_smm_enabled(X86MachineState *x86ms);
|
||||
bool x86_machine_is_acpi_enabled(X86MachineState *x86ms);
|
||||
bool x86_machine_is_smm_enabled(const X86MachineState *x86ms);
|
||||
bool x86_machine_is_acpi_enabled(const X86MachineState *x86ms);
|
||||
|
||||
/* Global System Interrupts */
|
||||
|
||||
|
Binary file not shown.
@ -28,6 +28,7 @@ blobs = files(
|
||||
'bios.bin',
|
||||
'bios-256k.bin',
|
||||
'bios-microvm.bin',
|
||||
'qboot.rom',
|
||||
'sgabios.bin',
|
||||
'vgabios.bin',
|
||||
'vgabios-cirrus.bin',
|
||||
|
BIN
pc-bios/qboot.rom
Normal file
BIN
pc-bios/qboot.rom
Normal file
Binary file not shown.
@ -68,13 +68,16 @@ default help:
|
||||
@echo " efi -- update UEFI (edk2) platform firmware"
|
||||
@echo " opensbi32-generic -- update OpenSBI for 32-bit generic machine"
|
||||
@echo " opensbi64-generic -- update OpenSBI for 64-bit generic machine"
|
||||
@echo " bios-microvm -- update bios-microvm.bin (qboot)"
|
||||
@echo " qboot -- update qboot"
|
||||
@echo " clean -- delete the files generated by the previous" \
|
||||
"build targets"
|
||||
|
||||
bios: build-seabios-config-seabios-128k build-seabios-config-seabios-256k
|
||||
bios: build-seabios-config-seabios-128k \
|
||||
build-seabios-config-seabios-256k \
|
||||
build-seabios-config-seabios-microvm
|
||||
cp seabios/builds/seabios-128k/bios.bin ../pc-bios/bios.bin
|
||||
cp seabios/builds/seabios-256k/bios.bin ../pc-bios/bios-256k.bin
|
||||
cp seabios/builds/seabios-microvm/bios.bin ../pc-bios/bios-microvm.bin
|
||||
|
||||
vgabios seavgabios: $(patsubst %,seavgabios-%,$(vgabios_variants))
|
||||
|
||||
@ -183,9 +186,9 @@ opensbi64-generic:
|
||||
cp opensbi/build/platform/generic/firmware/fw_dynamic.bin ../pc-bios/opensbi-riscv64-generic-fw_dynamic.bin
|
||||
cp opensbi/build/platform/generic/firmware/fw_dynamic.elf ../pc-bios/opensbi-riscv64-generic-fw_dynamic.elf
|
||||
|
||||
bios-microvm:
|
||||
qboot:
|
||||
$(MAKE) -C qboot
|
||||
cp qboot/bios.bin ../pc-bios/bios-microvm.bin
|
||||
cp qboot/bios.bin ../pc-bios/qboot.rom
|
||||
|
||||
npcm7xx_bootrom:
|
||||
$(MAKE) -C vbootrom CROSS_COMPILE=$(arm_cross_prefix)
|
||||
|
26
roms/config.seabios-microvm
Normal file
26
roms/config.seabios-microvm
Normal file
@ -0,0 +1,26 @@
|
||||
CONFIG_QEMU=y
|
||||
CONFIG_QEMU_HARDWARE=y
|
||||
CONFIG_PERMIT_UNALIGNED_PCIROM=y
|
||||
CONFIG_ROM_SIZE=128
|
||||
CONFIG_XEN=n
|
||||
CONFIG_BOOTSPLASH=n
|
||||
CONFIG_ATA=n
|
||||
CONFIG_AHCI=n
|
||||
CONFIG_SDCARD=n
|
||||
CONFIG_PVSCSI=n
|
||||
CONFIG_ESP_SCSI=n
|
||||
CONFIG_LSI_SCSI=n
|
||||
CONFIG_MEGASAS=n
|
||||
CONFIG_MPT_SCSI=n
|
||||
CONFIG_FLOPPY=n
|
||||
CONFIG_FLASH_FLOPPY=n
|
||||
CONFIG_NVME=n
|
||||
CONFIG_PS2PORT=n
|
||||
CONFIG_USB=n
|
||||
CONFIG_LPT=n
|
||||
CONFIG_RTC_TIMER=n
|
||||
CONFIG_USE_SMM=n
|
||||
CONFIG_PMTIMER=n
|
||||
CONFIG_TCGBIOS=n
|
||||
CONFIG_HARDWARE_IRQ=n
|
||||
CONFIG_ACPI_PARSE=y
|
BIN
tests/data/acpi/microvm/APIC
Normal file
BIN
tests/data/acpi/microvm/APIC
Normal file
Binary file not shown.
BIN
tests/data/acpi/microvm/DSDT
Normal file
BIN
tests/data/acpi/microvm/DSDT
Normal file
Binary file not shown.
BIN
tests/data/acpi/microvm/FACP
Normal file
BIN
tests/data/acpi/microvm/FACP
Normal file
Binary file not shown.
@ -72,6 +72,7 @@ typedef struct {
|
||||
const char *variant;
|
||||
const char *uefi_fl1;
|
||||
const char *uefi_fl2;
|
||||
const char *blkdev;
|
||||
const char *cd;
|
||||
const uint64_t ram_start;
|
||||
const uint64_t scan_len;
|
||||
@ -666,9 +667,10 @@ static void test_acpi_one(const char *params, test_data *data)
|
||||
args = g_strdup_printf("-machine %s,kernel-irqchip=off %s -accel tcg "
|
||||
"-net none -display none %s "
|
||||
"-drive id=hd0,if=none,file=%s,format=raw "
|
||||
"-device ide-hd,drive=hd0 ",
|
||||
"-device %s,drive=hd0 ",
|
||||
data->machine, data->tcg_only ? "" : "-accel kvm",
|
||||
params ? params : "", disk);
|
||||
params ? params : "", disk,
|
||||
data->blkdev ?: "ide-hd");
|
||||
}
|
||||
|
||||
data->qts = qtest_init(args);
|
||||
@ -1042,6 +1044,20 @@ static void test_acpi_virt_tcg_memhp(void)
|
||||
|
||||
}
|
||||
|
||||
static void test_acpi_microvm_tcg(void)
|
||||
{
|
||||
test_data data;
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.machine = "microvm";
|
||||
data.required_struct_types = NULL; /* no smbios */
|
||||
data.required_struct_types_len = 0;
|
||||
data.blkdev = "virtio-blk-device";
|
||||
test_acpi_one(" -machine microvm,acpi=on,rtc=off",
|
||||
&data);
|
||||
free_test_data(&data);
|
||||
}
|
||||
|
||||
static void test_acpi_virt_tcg_numamem(void)
|
||||
{
|
||||
test_data data = {
|
||||
@ -1159,6 +1175,7 @@ int main(int argc, char *argv[])
|
||||
qtest_add_func("acpi/q35/dimmpxm", test_acpi_q35_tcg_dimm_pxm);
|
||||
qtest_add_func("acpi/piix4/acpihmat", test_acpi_piix4_tcg_acpi_hmat);
|
||||
qtest_add_func("acpi/q35/acpihmat", test_acpi_q35_tcg_acpi_hmat);
|
||||
qtest_add_func("acpi/microvm", test_acpi_microvm_tcg);
|
||||
} else if (strcmp(arch, "aarch64") == 0) {
|
||||
qtest_add_func("acpi/virt", test_acpi_virt_tcg);
|
||||
qtest_add_func("acpi/virt/numamem", test_acpi_virt_tcg_numamem);
|
||||
|
Loading…
x
Reference in New Issue
Block a user