mirror of https://github.com/xemu-project/xemu.git
* small cleanups for pc-bios/optionrom Makefiles
* checkpatch: fix g_malloc check * fix mremap() and RDMA detection * confine igd-passthrough-isa-bridge to Xen-enabled builds * cover PCI in arm-virt machine qtests * add -M boot and -M mem compound properties * bump SLIRP submodule * support CFI with system libslirp (>= 4.7) * clean up CoQueue wakeup functions * fix vhost-vsock regression * fix --disable-vnc compilation * other minor bugfixes -----BEGIN PGP SIGNATURE----- iQFIBAABCAAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmJ8/KMUHHBib256aW5p QHJlZGhhdC5jb20ACgkQv/vSX3jHroNTTAf9Et1C8iZn+OlZi99wMEeMy8a4mIE5 CpkBpFphhkBvt3AH7XNsCyL4Gea4QgsI7nOIEVUwvW7gPf85PiBUX8mjrIVg3x1k bmMEwMKSTYPmDieAnYBP9zCqZQXNYP8L8WxVs2jFY2GXZ2ZogODYFbvCY4yEEB72 UR6uIvQRdpiB6BEj8UZ+5i+sDtb0zxqrjzUz8T/PJC9/2JSNgi+sAWWQoQT3PPU7 R7z2nmEa1VeVLPP6mUHvJKhBltVXF+LyIjQHvo+Tp9tSqp9JwXfFBNQ5W/MFes2D skF47N7PdgKRH9Dp4r0j+MqBwoAq86+ao+MKsbQ1Gb91HhoCWt/MrVrVyg== =1E6P -----END PGP SIGNATURE----- Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging * small cleanups for pc-bios/optionrom Makefiles * checkpatch: fix g_malloc check * fix mremap() and RDMA detection * confine igd-passthrough-isa-bridge to Xen-enabled builds * cover PCI in arm-virt machine qtests * add -M boot and -M mem compound properties * bump SLIRP submodule * support CFI with system libslirp (>= 4.7) * clean up CoQueue wakeup functions * fix vhost-vsock regression * fix --disable-vnc compilation * other minor bugfixes # -----BEGIN PGP SIGNATURE----- # # iQFIBAABCAAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmJ8/KMUHHBib256aW5p # QHJlZGhhdC5jb20ACgkQv/vSX3jHroNTTAf9Et1C8iZn+OlZi99wMEeMy8a4mIE5 # CpkBpFphhkBvt3AH7XNsCyL4Gea4QgsI7nOIEVUwvW7gPf85PiBUX8mjrIVg3x1k # bmMEwMKSTYPmDieAnYBP9zCqZQXNYP8L8WxVs2jFY2GXZ2ZogODYFbvCY4yEEB72 # UR6uIvQRdpiB6BEj8UZ+5i+sDtb0zxqrjzUz8T/PJC9/2JSNgi+sAWWQoQT3PPU7 # R7z2nmEa1VeVLPP6mUHvJKhBltVXF+LyIjQHvo+Tp9tSqp9JwXfFBNQ5W/MFes2D # skF47N7PdgKRH9Dp4r0j+MqBwoAq86+ao+MKsbQ1Gb91HhoCWt/MrVrVyg== # =1E6P # -----END PGP SIGNATURE----- # gpg: Signature made Thu 12 May 2022 05:25:07 AM PDT # gpg: using RSA key F13338574B662389866C7682BFFBD25F78C7AE83 # gpg: issuer "pbonzini@redhat.com" # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [undefined] # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" [undefined] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1 # Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83 * tag 'for-upstream' of https://gitlab.com/bonzini/qemu: (27 commits) vmxcap: add tertiary execution controls vl: make machine type deprecation a warning meson: link libpng independent of vnc vhost-backend: do not depend on CONFIG_VHOST_VSOCK coroutine-lock: qemu_co_queue_restart_all is a coroutine-only qemu_co_enter_all coroutine-lock: introduce qemu_co_queue_enter_all coroutine-lock: qemu_co_queue_next is a coroutine-only qemu_co_enter_next net: slirp: allow CFI with libslirp >= 4.7 net: slirp: add support for CFI-friendly timer API net: slirp: switch to slirp_new net: slirp: introduce a wrapper struct for QemuTimer slirp: bump submodule past 4.7 release machine: move more memory validation to Machine object machine: make memory-backend a link property machine: add mem compound property machine: add boot compound property machine: use QAPI struct for boot configuration tests/qtest/libqos: Add generic pci host bridge in arm-virt machine tests/qtest/libqos: Skip hotplug tests if pci root bus is not hotpluggable tests/qtest/libqos/pci: Introduce pio_limit ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
9de5f2b408
|
@ -751,7 +751,7 @@ void bdrv_drain_all(void)
|
||||||
*
|
*
|
||||||
* This function should be called when a tracked request is completing.
|
* This function should be called when a tracked request is completing.
|
||||||
*/
|
*/
|
||||||
static void tracked_request_end(BdrvTrackedRequest *req)
|
static void coroutine_fn tracked_request_end(BdrvTrackedRequest *req)
|
||||||
{
|
{
|
||||||
if (req->serialising) {
|
if (req->serialising) {
|
||||||
qatomic_dec(&req->bs->serialising_in_flight);
|
qatomic_dec(&req->bs->serialising_in_flight);
|
||||||
|
|
|
@ -2038,7 +2038,6 @@ echo "CCAS=$ccas" >> $config_host_mak
|
||||||
echo "CPP=$cpp" >> $config_host_mak
|
echo "CPP=$cpp" >> $config_host_mak
|
||||||
echo "OBJCOPY=$objcopy" >> $config_host_mak
|
echo "OBJCOPY=$objcopy" >> $config_host_mak
|
||||||
echo "LD=$ld" >> $config_host_mak
|
echo "LD=$ld" >> $config_host_mak
|
||||||
echo "CFLAGS_NOPIE=$CFLAGS_NOPIE" >> $config_host_mak
|
|
||||||
echo "QEMU_CFLAGS=$QEMU_CFLAGS" >> $config_host_mak
|
echo "QEMU_CFLAGS=$QEMU_CFLAGS" >> $config_host_mak
|
||||||
echo "QEMU_CXXFLAGS=$QEMU_CXXFLAGS" >> $config_host_mak
|
echo "QEMU_CXXFLAGS=$QEMU_CXXFLAGS" >> $config_host_mak
|
||||||
echo "QEMU_OBJCFLAGS=$QEMU_OBJCFLAGS" >> $config_host_mak
|
echo "QEMU_OBJCFLAGS=$QEMU_OBJCFLAGS" >> $config_host_mak
|
||||||
|
|
|
@ -1365,7 +1365,7 @@ static void n8x0_init(MachineState *machine,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (option_rom[0].name &&
|
if (option_rom[0].name &&
|
||||||
(machine->boot_order[0] == 'n' || !machine->kernel_filename)) {
|
(machine->boot_config.order[0] == 'n' || !machine->kernel_filename)) {
|
||||||
uint8_t *nolo_tags = g_new(uint8_t, 0x10000);
|
uint8_t *nolo_tags = g_new(uint8_t, 0x10000);
|
||||||
/* No, wait, better start at the ROM. */
|
/* No, wait, better start at the ROM. */
|
||||||
s->mpu->cpu->env.regs[15] = OMAP2_Q2_BASE + 0x400000;
|
s->mpu->cpu->env.regs[15] = OMAP2_Q2_BASE + 0x400000;
|
||||||
|
|
|
@ -21,12 +21,14 @@
|
||||||
#include "qapi/qapi-visit-common.h"
|
#include "qapi/qapi-visit-common.h"
|
||||||
#include "qapi/qapi-visit-machine.h"
|
#include "qapi/qapi-visit-machine.h"
|
||||||
#include "qapi/visitor.h"
|
#include "qapi/visitor.h"
|
||||||
|
#include "qom/object_interfaces.h"
|
||||||
#include "hw/sysbus.h"
|
#include "hw/sysbus.h"
|
||||||
#include "sysemu/cpus.h"
|
#include "sysemu/cpus.h"
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
#include "sysemu/reset.h"
|
#include "sysemu/reset.h"
|
||||||
#include "sysemu/runstate.h"
|
#include "sysemu/runstate.h"
|
||||||
#include "sysemu/numa.h"
|
#include "sysemu/numa.h"
|
||||||
|
#include "sysemu/xen.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
#include "sysemu/qtest.h"
|
#include "sysemu/qtest.h"
|
||||||
#include "hw/pci/pci.h"
|
#include "hw/pci/pci.h"
|
||||||
|
@ -36,6 +38,7 @@
|
||||||
#include "exec/confidential-guest-support.h"
|
#include "exec/confidential-guest-support.h"
|
||||||
#include "hw/virtio/virtio.h"
|
#include "hw/virtio/virtio.h"
|
||||||
#include "hw/virtio/virtio-pci.h"
|
#include "hw/virtio/virtio-pci.h"
|
||||||
|
#include "qom/object_interfaces.h"
|
||||||
|
|
||||||
GlobalProperty hw_compat_7_0[] = {};
|
GlobalProperty hw_compat_7_0[] = {};
|
||||||
const size_t hw_compat_7_0_len = G_N_ELEMENTS(hw_compat_7_0);
|
const size_t hw_compat_7_0_len = G_N_ELEMENTS(hw_compat_7_0);
|
||||||
|
@ -523,6 +526,78 @@ static void machine_set_hmat(Object *obj, bool value, Error **errp)
|
||||||
ms->numa_state->hmat_enabled = value;
|
ms->numa_state->hmat_enabled = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void machine_get_mem(Object *obj, Visitor *v, const char *name,
|
||||||
|
void *opaque, Error **errp)
|
||||||
|
{
|
||||||
|
MachineState *ms = MACHINE(obj);
|
||||||
|
MemorySizeConfiguration mem = {
|
||||||
|
.has_size = true,
|
||||||
|
.size = ms->ram_size,
|
||||||
|
.has_max_size = !!ms->ram_slots,
|
||||||
|
.max_size = ms->maxram_size,
|
||||||
|
.has_slots = !!ms->ram_slots,
|
||||||
|
.slots = ms->ram_slots,
|
||||||
|
};
|
||||||
|
MemorySizeConfiguration *p_mem = &mem;
|
||||||
|
|
||||||
|
visit_type_MemorySizeConfiguration(v, name, &p_mem, &error_abort);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void machine_set_mem(Object *obj, Visitor *v, const char *name,
|
||||||
|
void *opaque, Error **errp)
|
||||||
|
{
|
||||||
|
MachineState *ms = MACHINE(obj);
|
||||||
|
MachineClass *mc = MACHINE_GET_CLASS(obj);
|
||||||
|
MemorySizeConfiguration *mem;
|
||||||
|
|
||||||
|
ERRP_GUARD();
|
||||||
|
|
||||||
|
if (!visit_type_MemorySizeConfiguration(v, name, &mem, errp)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mem->has_size) {
|
||||||
|
mem->has_size = true;
|
||||||
|
mem->size = mc->default_ram_size;
|
||||||
|
}
|
||||||
|
mem->size = QEMU_ALIGN_UP(mem->size, 8192);
|
||||||
|
if (mc->fixup_ram_size) {
|
||||||
|
mem->size = mc->fixup_ram_size(mem->size);
|
||||||
|
}
|
||||||
|
if ((ram_addr_t)mem->size != mem->size) {
|
||||||
|
error_setg(errp, "ram size too large");
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mem->has_max_size) {
|
||||||
|
if (mem->max_size < mem->size) {
|
||||||
|
error_setg(errp, "invalid value of maxmem: "
|
||||||
|
"maximum memory size (0x%" PRIx64 ") must be at least "
|
||||||
|
"the initial memory size (0x%" PRIx64 ")",
|
||||||
|
mem->max_size, mem->size);
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
if (mem->has_slots && mem->slots && mem->max_size == mem->size) {
|
||||||
|
error_setg(errp, "invalid value of maxmem: "
|
||||||
|
"memory slots were specified but maximum memory size "
|
||||||
|
"(0x%" PRIx64 ") is equal to the initial memory size "
|
||||||
|
"(0x%" PRIx64 ")", mem->max_size, mem->size);
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
ms->maxram_size = mem->max_size;
|
||||||
|
} else {
|
||||||
|
if (mem->has_slots) {
|
||||||
|
error_setg(errp, "slots specified but no max-size");
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
ms->maxram_size = mem->size;
|
||||||
|
}
|
||||||
|
ms->ram_size = mem->size;
|
||||||
|
ms->ram_slots = mem->has_slots ? mem->slots : 0;
|
||||||
|
out_free:
|
||||||
|
qapi_free_MemorySizeConfiguration(mem);
|
||||||
|
}
|
||||||
|
|
||||||
static char *machine_get_nvdimm_persistence(Object *obj, Error **errp)
|
static char *machine_get_nvdimm_persistence(Object *obj, Error **errp)
|
||||||
{
|
{
|
||||||
MachineState *ms = MACHINE(obj);
|
MachineState *ms = MACHINE(obj);
|
||||||
|
@ -581,21 +656,6 @@ bool device_type_is_dynamic_sysbus(MachineClass *mc, const char *type)
|
||||||
return allowed;
|
return allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *machine_get_memdev(Object *obj, Error **errp)
|
|
||||||
{
|
|
||||||
MachineState *ms = MACHINE(obj);
|
|
||||||
|
|
||||||
return g_strdup(ms->ram_memdev_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void machine_set_memdev(Object *obj, const char *value, Error **errp)
|
|
||||||
{
|
|
||||||
MachineState *ms = MACHINE(obj);
|
|
||||||
|
|
||||||
g_free(ms->ram_memdev_id);
|
|
||||||
ms->ram_memdev_id = g_strdup(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
HotpluggableCPUList *machine_query_hotpluggable_cpus(MachineState *machine)
|
HotpluggableCPUList *machine_query_hotpluggable_cpus(MachineState *machine)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -784,6 +844,65 @@ static void machine_set_smp(Object *obj, Visitor *v, const char *name,
|
||||||
machine_parse_smp_config(ms, config, errp);
|
machine_parse_smp_config(ms, config, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void machine_get_boot(Object *obj, Visitor *v, const char *name,
|
||||||
|
void *opaque, Error **errp)
|
||||||
|
{
|
||||||
|
MachineState *ms = MACHINE(obj);
|
||||||
|
BootConfiguration *config = &ms->boot_config;
|
||||||
|
visit_type_BootConfiguration(v, name, &config, &error_abort);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void machine_free_boot_config(MachineState *ms)
|
||||||
|
{
|
||||||
|
g_free(ms->boot_config.order);
|
||||||
|
g_free(ms->boot_config.once);
|
||||||
|
g_free(ms->boot_config.splash);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void machine_copy_boot_config(MachineState *ms, BootConfiguration *config)
|
||||||
|
{
|
||||||
|
MachineClass *machine_class = MACHINE_GET_CLASS(ms);
|
||||||
|
|
||||||
|
machine_free_boot_config(ms);
|
||||||
|
ms->boot_config = *config;
|
||||||
|
if (!config->has_order) {
|
||||||
|
ms->boot_config.has_order = true;
|
||||||
|
ms->boot_config.order = g_strdup(machine_class->default_boot_order);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void machine_set_boot(Object *obj, Visitor *v, const char *name,
|
||||||
|
void *opaque, Error **errp)
|
||||||
|
{
|
||||||
|
ERRP_GUARD();
|
||||||
|
MachineState *ms = MACHINE(obj);
|
||||||
|
BootConfiguration *config = NULL;
|
||||||
|
|
||||||
|
if (!visit_type_BootConfiguration(v, name, &config, errp)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (config->has_order) {
|
||||||
|
validate_bootdevices(config->order, errp);
|
||||||
|
if (*errp) {
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (config->has_once) {
|
||||||
|
validate_bootdevices(config->once, errp);
|
||||||
|
if (*errp) {
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
machine_copy_boot_config(ms, config);
|
||||||
|
/* Strings live in ms->boot_config. */
|
||||||
|
free(config);
|
||||||
|
return;
|
||||||
|
|
||||||
|
out_free:
|
||||||
|
qapi_free_BootConfiguration(config);
|
||||||
|
}
|
||||||
|
|
||||||
static void machine_class_init(ObjectClass *oc, void *data)
|
static void machine_class_init(ObjectClass *oc, void *data)
|
||||||
{
|
{
|
||||||
MachineClass *mc = MACHINE_CLASS(oc);
|
MachineClass *mc = MACHINE_CLASS(oc);
|
||||||
|
@ -822,6 +941,12 @@ static void machine_class_init(ObjectClass *oc, void *data)
|
||||||
object_class_property_set_description(oc, "dumpdtb",
|
object_class_property_set_description(oc, "dumpdtb",
|
||||||
"Dump current dtb to a file and quit");
|
"Dump current dtb to a file and quit");
|
||||||
|
|
||||||
|
object_class_property_add(oc, "boot", "BootConfiguration",
|
||||||
|
machine_get_boot, machine_set_boot,
|
||||||
|
NULL, NULL);
|
||||||
|
object_class_property_set_description(oc, "boot",
|
||||||
|
"Boot configuration");
|
||||||
|
|
||||||
object_class_property_add(oc, "smp", "SMPConfiguration",
|
object_class_property_add(oc, "smp", "SMPConfiguration",
|
||||||
machine_get_smp, machine_set_smp,
|
machine_get_smp, machine_set_smp,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
|
@ -883,11 +1008,18 @@ static void machine_class_init(ObjectClass *oc, void *data)
|
||||||
object_class_property_set_description(oc, "memory-encryption",
|
object_class_property_set_description(oc, "memory-encryption",
|
||||||
"Set memory encryption object to use");
|
"Set memory encryption object to use");
|
||||||
|
|
||||||
object_class_property_add_str(oc, "memory-backend",
|
object_class_property_add_link(oc, "memory-backend", TYPE_MEMORY_BACKEND,
|
||||||
machine_get_memdev, machine_set_memdev);
|
offsetof(MachineState, memdev), object_property_allow_set_link,
|
||||||
|
OBJ_PROP_LINK_STRONG);
|
||||||
object_class_property_set_description(oc, "memory-backend",
|
object_class_property_set_description(oc, "memory-backend",
|
||||||
"Set RAM backend"
|
"Set RAM backend"
|
||||||
"Valid value is ID of hostmem based backend");
|
"Valid value is ID of hostmem based backend");
|
||||||
|
|
||||||
|
object_class_property_add(oc, "memory", "MemorySizeConfiguration",
|
||||||
|
machine_get_mem, machine_set_mem,
|
||||||
|
NULL, NULL);
|
||||||
|
object_class_property_set_description(oc, "memory",
|
||||||
|
"Memory size configuration");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void machine_class_base_init(ObjectClass *oc, void *data)
|
static void machine_class_base_init(ObjectClass *oc, void *data)
|
||||||
|
@ -918,6 +1050,8 @@ static void machine_initfn(Object *obj)
|
||||||
ms->mem_merge = true;
|
ms->mem_merge = true;
|
||||||
ms->enable_graphics = true;
|
ms->enable_graphics = true;
|
||||||
ms->kernel_cmdline = g_strdup("");
|
ms->kernel_cmdline = g_strdup("");
|
||||||
|
ms->ram_size = mc->default_ram_size;
|
||||||
|
ms->maxram_size = mc->default_ram_size;
|
||||||
|
|
||||||
if (mc->nvdimm_supported) {
|
if (mc->nvdimm_supported) {
|
||||||
Object *obj = OBJECT(ms);
|
Object *obj = OBJECT(ms);
|
||||||
|
@ -955,12 +1089,15 @@ static void machine_initfn(Object *obj)
|
||||||
ms->smp.clusters = 1;
|
ms->smp.clusters = 1;
|
||||||
ms->smp.cores = 1;
|
ms->smp.cores = 1;
|
||||||
ms->smp.threads = 1;
|
ms->smp.threads = 1;
|
||||||
|
|
||||||
|
machine_copy_boot_config(ms, &(BootConfiguration){ 0 });
|
||||||
}
|
}
|
||||||
|
|
||||||
static void machine_finalize(Object *obj)
|
static void machine_finalize(Object *obj)
|
||||||
{
|
{
|
||||||
MachineState *ms = MACHINE(obj);
|
MachineState *ms = MACHINE(obj);
|
||||||
|
|
||||||
|
machine_free_boot_config(ms);
|
||||||
g_free(ms->kernel_filename);
|
g_free(ms->kernel_filename);
|
||||||
g_free(ms->initrd_filename);
|
g_free(ms->initrd_filename);
|
||||||
g_free(ms->kernel_cmdline);
|
g_free(ms->kernel_cmdline);
|
||||||
|
@ -1122,7 +1259,40 @@ MemoryRegion *machine_consume_memdev(MachineState *machine,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void machine_run_board_init(MachineState *machine)
|
static bool create_default_memdev(MachineState *ms, const char *path, Error **errp)
|
||||||
|
{
|
||||||
|
Object *obj;
|
||||||
|
MachineClass *mc = MACHINE_GET_CLASS(ms);
|
||||||
|
bool r = false;
|
||||||
|
|
||||||
|
obj = object_new(path ? TYPE_MEMORY_BACKEND_FILE : TYPE_MEMORY_BACKEND_RAM);
|
||||||
|
if (path) {
|
||||||
|
if (!object_property_set_str(obj, "mem-path", path, errp)) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!object_property_set_int(obj, "size", ms->ram_size, errp)) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
object_property_add_child(object_get_objects_root(), mc->default_ram_id,
|
||||||
|
obj);
|
||||||
|
/* Ensure backend's memory region name is equal to mc->default_ram_id */
|
||||||
|
if (!object_property_set_bool(obj, "x-use-canonical-path-for-ramblock-id",
|
||||||
|
false, errp)) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (!user_creatable_complete(USER_CREATABLE(obj), errp)) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
r = object_property_set_link(OBJECT(ms), "memory-backend", obj, errp);
|
||||||
|
|
||||||
|
out:
|
||||||
|
object_unref(obj);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void machine_run_board_init(MachineState *machine, const char *mem_path, Error **errp)
|
||||||
{
|
{
|
||||||
MachineClass *machine_class = MACHINE_GET_CLASS(machine);
|
MachineClass *machine_class = MACHINE_GET_CLASS(machine);
|
||||||
ObjectClass *oc = object_class_by_name(machine->cpu_type);
|
ObjectClass *oc = object_class_by_name(machine->cpu_type);
|
||||||
|
@ -1133,11 +1303,26 @@ void machine_run_board_init(MachineState *machine)
|
||||||
clock values from the log. */
|
clock values from the log. */
|
||||||
replay_checkpoint(CHECKPOINT_INIT);
|
replay_checkpoint(CHECKPOINT_INIT);
|
||||||
|
|
||||||
if (machine->ram_memdev_id) {
|
if (!xen_enabled()) {
|
||||||
Object *o;
|
/* On 32-bit hosts, QEMU is limited by virtual address space */
|
||||||
o = object_resolve_path_type(machine->ram_memdev_id,
|
if (machine->ram_size > (2047 << 20) && HOST_LONG_BITS == 32) {
|
||||||
TYPE_MEMORY_BACKEND, NULL);
|
error_setg(errp, "at most 2047 MB RAM can be simulated");
|
||||||
machine->ram = machine_consume_memdev(machine, MEMORY_BACKEND(o));
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (machine->memdev) {
|
||||||
|
ram_addr_t backend_size = object_property_get_uint(OBJECT(machine->memdev),
|
||||||
|
"size", &error_abort);
|
||||||
|
if (backend_size != machine->ram_size) {
|
||||||
|
error_setg(errp, "Machine memory size does not match the size of the memory backend");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (machine_class->default_ram_id && machine->ram_size &&
|
||||||
|
numa_uses_legacy_mem()) {
|
||||||
|
if (!create_default_memdev(current_machine, mem_path, errp)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (machine->numa_state) {
|
if (machine->numa_state) {
|
||||||
|
@ -1147,6 +1332,10 @@ void machine_run_board_init(MachineState *machine)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!machine->ram && machine->memdev) {
|
||||||
|
machine->ram = machine_consume_memdev(machine, machine->memdev);
|
||||||
|
}
|
||||||
|
|
||||||
/* If the machine supports the valid_cpu_types check and the user
|
/* If the machine supports the valid_cpu_types check and the user
|
||||||
* specified a CPU with -cpu check here that the user CPU is supported.
|
* specified a CPU with -cpu check here that the user CPU is supported.
|
||||||
*/
|
*/
|
||||||
|
@ -1229,9 +1418,9 @@ void qdev_machine_creation_done(void)
|
||||||
{
|
{
|
||||||
cpu_synchronize_all_post_init();
|
cpu_synchronize_all_post_init();
|
||||||
|
|
||||||
if (current_machine->boot_once) {
|
if (current_machine->boot_config.has_once) {
|
||||||
qemu_boot_set(current_machine->boot_once, &error_fatal);
|
qemu_boot_set(current_machine->boot_config.once, &error_fatal);
|
||||||
qemu_register_reset(restore_boot_order, g_strdup(current_machine->boot_order));
|
qemu_register_reset(restore_boot_order, g_strdup(current_machine->boot_config.order));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -695,7 +695,7 @@ void numa_complete_configuration(MachineState *ms)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!numa_uses_legacy_mem() && mc->default_ram_id) {
|
if (!numa_uses_legacy_mem() && mc->default_ram_id) {
|
||||||
if (ms->ram_memdev_id) {
|
if (ms->memdev) {
|
||||||
error_report("'-machine memory-backend' and '-numa memdev'"
|
error_report("'-machine memory-backend' and '-numa memdev'"
|
||||||
" properties are mutually exclusive");
|
" properties are mutually exclusive");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
|
@ -147,7 +147,7 @@ static FWCfgState *create_fw_cfg(MachineState *ms)
|
||||||
fw_cfg_add_file(fw_cfg, "/etc/power-button-addr",
|
fw_cfg_add_file(fw_cfg, "/etc/power-button-addr",
|
||||||
g_memdup(&val, sizeof(val)), sizeof(val));
|
g_memdup(&val, sizeof(val)), sizeof(val));
|
||||||
|
|
||||||
fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, ms->boot_order[0]);
|
fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, ms->boot_config.order[0]);
|
||||||
qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
|
qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
|
||||||
|
|
||||||
return fw_cfg;
|
return fw_cfg;
|
||||||
|
@ -391,8 +391,8 @@ static void machine_hppa_init(MachineState *machine)
|
||||||
* mode (kernel_entry=1), and to boot from CD (gr[24]='d')
|
* mode (kernel_entry=1), and to boot from CD (gr[24]='d')
|
||||||
* or hard disc * (gr[24]='c').
|
* or hard disc * (gr[24]='c').
|
||||||
*/
|
*/
|
||||||
kernel_entry = boot_menu ? 1 : 0;
|
kernel_entry = machine->boot_config.has_menu ? machine->boot_config.menu : 0;
|
||||||
cpu[0]->env.gr[24] = machine->boot_order[0];
|
cpu[0]->env.gr[24] = machine->boot_config.order[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We jump to the firmware entry routine and pass the
|
/* We jump to the firmware entry routine and pass the
|
||||||
|
|
|
@ -675,7 +675,7 @@ void pc_cmos_init(PCMachineState *pcms,
|
||||||
object_property_set_link(OBJECT(pcms), "rtc_state", OBJECT(s),
|
object_property_set_link(OBJECT(pcms), "rtc_state", OBJECT(s),
|
||||||
&error_abort);
|
&error_abort);
|
||||||
|
|
||||||
set_boot_dev(s, MACHINE(pcms)->boot_order, &error_fatal);
|
set_boot_dev(s, MACHINE(pcms)->boot_config.order, &error_fatal);
|
||||||
|
|
||||||
val = 0;
|
val = 0;
|
||||||
val |= 0x02; /* FPU is there */
|
val |= 0x02; /* FPU is there */
|
||||||
|
|
|
@ -813,124 +813,6 @@ static void pc_i440fx_1_4_machine_options(MachineClass *m)
|
||||||
DEFINE_I440FX_MACHINE(v1_4, "pc-i440fx-1.4", pc_compat_1_4_fn,
|
DEFINE_I440FX_MACHINE(v1_4, "pc-i440fx-1.4", pc_compat_1_4_fn,
|
||||||
pc_i440fx_1_4_machine_options);
|
pc_i440fx_1_4_machine_options);
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint16_t gpu_device_id;
|
|
||||||
uint16_t pch_device_id;
|
|
||||||
uint8_t pch_revision_id;
|
|
||||||
} IGDDeviceIDInfo;
|
|
||||||
|
|
||||||
/* In real world different GPU should have different PCH. But actually
|
|
||||||
* the different PCH DIDs likely map to different PCH SKUs. We do the
|
|
||||||
* same thing for the GPU. For PCH, the different SKUs are going to be
|
|
||||||
* all the same silicon design and implementation, just different
|
|
||||||
* features turn on and off with fuses. The SW interfaces should be
|
|
||||||
* consistent across all SKUs in a given family (eg LPT). But just same
|
|
||||||
* features may not be supported.
|
|
||||||
*
|
|
||||||
* Most of these different PCH features probably don't matter to the
|
|
||||||
* Gfx driver, but obviously any difference in display port connections
|
|
||||||
* will so it should be fine with any PCH in case of passthrough.
|
|
||||||
*
|
|
||||||
* So currently use one PCH version, 0x8c4e, to cover all HSW(Haswell)
|
|
||||||
* scenarios, 0x9cc3 for BDW(Broadwell).
|
|
||||||
*/
|
|
||||||
static const IGDDeviceIDInfo igd_combo_id_infos[] = {
|
|
||||||
/* HSW Classic */
|
|
||||||
{0x0402, 0x8c4e, 0x04}, /* HSWGT1D, HSWD_w7 */
|
|
||||||
{0x0406, 0x8c4e, 0x04}, /* HSWGT1M, HSWM_w7 */
|
|
||||||
{0x0412, 0x8c4e, 0x04}, /* HSWGT2D, HSWD_w7 */
|
|
||||||
{0x0416, 0x8c4e, 0x04}, /* HSWGT2M, HSWM_w7 */
|
|
||||||
{0x041E, 0x8c4e, 0x04}, /* HSWGT15D, HSWD_w7 */
|
|
||||||
/* HSW ULT */
|
|
||||||
{0x0A06, 0x8c4e, 0x04}, /* HSWGT1UT, HSWM_w7 */
|
|
||||||
{0x0A16, 0x8c4e, 0x04}, /* HSWGT2UT, HSWM_w7 */
|
|
||||||
{0x0A26, 0x8c4e, 0x06}, /* HSWGT3UT, HSWM_w7 */
|
|
||||||
{0x0A2E, 0x8c4e, 0x04}, /* HSWGT3UT28W, HSWM_w7 */
|
|
||||||
{0x0A1E, 0x8c4e, 0x04}, /* HSWGT2UX, HSWM_w7 */
|
|
||||||
{0x0A0E, 0x8c4e, 0x04}, /* HSWGT1ULX, HSWM_w7 */
|
|
||||||
/* HSW CRW */
|
|
||||||
{0x0D26, 0x8c4e, 0x04}, /* HSWGT3CW, HSWM_w7 */
|
|
||||||
{0x0D22, 0x8c4e, 0x04}, /* HSWGT3CWDT, HSWD_w7 */
|
|
||||||
/* HSW Server */
|
|
||||||
{0x041A, 0x8c4e, 0x04}, /* HSWSVGT2, HSWD_w7 */
|
|
||||||
/* HSW SRVR */
|
|
||||||
{0x040A, 0x8c4e, 0x04}, /* HSWSVGT1, HSWD_w7 */
|
|
||||||
/* BSW */
|
|
||||||
{0x1606, 0x9cc3, 0x03}, /* BDWULTGT1, BDWM_w7 */
|
|
||||||
{0x1616, 0x9cc3, 0x03}, /* BDWULTGT2, BDWM_w7 */
|
|
||||||
{0x1626, 0x9cc3, 0x03}, /* BDWULTGT3, BDWM_w7 */
|
|
||||||
{0x160E, 0x9cc3, 0x03}, /* BDWULXGT1, BDWM_w7 */
|
|
||||||
{0x161E, 0x9cc3, 0x03}, /* BDWULXGT2, BDWM_w7 */
|
|
||||||
{0x1602, 0x9cc3, 0x03}, /* BDWHALOGT1, BDWM_w7 */
|
|
||||||
{0x1612, 0x9cc3, 0x03}, /* BDWHALOGT2, BDWM_w7 */
|
|
||||||
{0x1622, 0x9cc3, 0x03}, /* BDWHALOGT3, BDWM_w7 */
|
|
||||||
{0x162B, 0x9cc3, 0x03}, /* BDWHALO28W, BDWM_w7 */
|
|
||||||
{0x162A, 0x9cc3, 0x03}, /* BDWGT3WRKS, BDWM_w7 */
|
|
||||||
{0x162D, 0x9cc3, 0x03}, /* BDWGT3SRVR, BDWM_w7 */
|
|
||||||
};
|
|
||||||
|
|
||||||
static void isa_bridge_class_init(ObjectClass *klass, void *data)
|
|
||||||
{
|
|
||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
|
||||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
|
||||||
|
|
||||||
dc->desc = "ISA bridge faked to support IGD PT";
|
|
||||||
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
|
|
||||||
k->vendor_id = PCI_VENDOR_ID_INTEL;
|
|
||||||
k->class_id = PCI_CLASS_BRIDGE_ISA;
|
|
||||||
};
|
|
||||||
|
|
||||||
static const TypeInfo isa_bridge_info = {
|
|
||||||
.name = "igd-passthrough-isa-bridge",
|
|
||||||
.parent = TYPE_PCI_DEVICE,
|
|
||||||
.instance_size = sizeof(PCIDevice),
|
|
||||||
.class_init = isa_bridge_class_init,
|
|
||||||
.interfaces = (InterfaceInfo[]) {
|
|
||||||
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
|
|
||||||
{ },
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
static void pt_graphics_register_types(void)
|
|
||||||
{
|
|
||||||
type_register_static(&isa_bridge_info);
|
|
||||||
}
|
|
||||||
type_init(pt_graphics_register_types)
|
|
||||||
|
|
||||||
void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id)
|
|
||||||
{
|
|
||||||
struct PCIDevice *bridge_dev;
|
|
||||||
int i, num;
|
|
||||||
uint16_t pch_dev_id = 0xffff;
|
|
||||||
uint8_t pch_rev_id = 0;
|
|
||||||
|
|
||||||
num = ARRAY_SIZE(igd_combo_id_infos);
|
|
||||||
for (i = 0; i < num; i++) {
|
|
||||||
if (gpu_dev_id == igd_combo_id_infos[i].gpu_device_id) {
|
|
||||||
pch_dev_id = igd_combo_id_infos[i].pch_device_id;
|
|
||||||
pch_rev_id = igd_combo_id_infos[i].pch_revision_id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pch_dev_id == 0xffff) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Currently IGD drivers always need to access PCH by 1f.0. */
|
|
||||||
bridge_dev = pci_create_simple(bus, PCI_DEVFN(0x1f, 0),
|
|
||||||
"igd-passthrough-isa-bridge");
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Note that vendor id is always PCI_VENDOR_ID_INTEL.
|
|
||||||
*/
|
|
||||||
if (!bridge_dev) {
|
|
||||||
fprintf(stderr, "set igd-passthrough-isa-bridge failed!\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pci_config_set_device_id(bridge_dev->config, pch_dev_id);
|
|
||||||
pci_config_set_revision(bridge_dev->config, pch_rev_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_ISAPC
|
#ifdef CONFIG_ISAPC
|
||||||
static void isapc_machine_options(MachineClass *m)
|
static void isapc_machine_options(MachineClass *m)
|
||||||
{
|
{
|
||||||
|
|
|
@ -178,21 +178,13 @@ error:
|
||||||
|
|
||||||
static void fw_cfg_bootsplash(FWCfgState *s)
|
static void fw_cfg_bootsplash(FWCfgState *s)
|
||||||
{
|
{
|
||||||
const char *boot_splash_filename = NULL;
|
|
||||||
const char *boot_splash_time = NULL;
|
|
||||||
char *filename, *file_data;
|
char *filename, *file_data;
|
||||||
gsize file_size;
|
gsize file_size;
|
||||||
int file_type;
|
int file_type;
|
||||||
|
|
||||||
/* get user configuration */
|
|
||||||
QemuOptsList *plist = qemu_find_opts("boot-opts");
|
|
||||||
QemuOpts *opts = QTAILQ_FIRST(&plist->head);
|
|
||||||
boot_splash_filename = qemu_opt_get(opts, "splash");
|
|
||||||
boot_splash_time = qemu_opt_get(opts, "splash-time");
|
|
||||||
|
|
||||||
/* insert splash time if user configurated */
|
/* insert splash time if user configurated */
|
||||||
if (boot_splash_time) {
|
if (current_machine->boot_config.has_splash_time) {
|
||||||
int64_t bst_val = qemu_opt_get_number(opts, "splash-time", -1);
|
int64_t bst_val = current_machine->boot_config.splash_time;
|
||||||
uint16_t bst_le16;
|
uint16_t bst_le16;
|
||||||
|
|
||||||
/* validate the input */
|
/* validate the input */
|
||||||
|
@ -208,7 +200,8 @@ static void fw_cfg_bootsplash(FWCfgState *s)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* insert splash file if user configurated */
|
/* insert splash file if user configurated */
|
||||||
if (boot_splash_filename) {
|
if (current_machine->boot_config.has_splash) {
|
||||||
|
const char *boot_splash_filename = current_machine->boot_config.splash;
|
||||||
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, boot_splash_filename);
|
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, boot_splash_filename);
|
||||||
if (filename == NULL) {
|
if (filename == NULL) {
|
||||||
error_report("failed to find file '%s'", boot_splash_filename);
|
error_report("failed to find file '%s'", boot_splash_filename);
|
||||||
|
@ -238,17 +231,11 @@ static void fw_cfg_bootsplash(FWCfgState *s)
|
||||||
|
|
||||||
static void fw_cfg_reboot(FWCfgState *s)
|
static void fw_cfg_reboot(FWCfgState *s)
|
||||||
{
|
{
|
||||||
const char *reboot_timeout = NULL;
|
|
||||||
uint64_t rt_val = -1;
|
uint64_t rt_val = -1;
|
||||||
uint32_t rt_le32;
|
uint32_t rt_le32;
|
||||||
|
|
||||||
/* get user configuration */
|
if (current_machine->boot_config.has_reboot_timeout) {
|
||||||
QemuOptsList *plist = qemu_find_opts("boot-opts");
|
rt_val = current_machine->boot_config.reboot_timeout;
|
||||||
QemuOpts *opts = QTAILQ_FIRST(&plist->head);
|
|
||||||
reboot_timeout = qemu_opt_get(opts, "reboot-timeout");
|
|
||||||
|
|
||||||
if (reboot_timeout) {
|
|
||||||
rt_val = qemu_opt_get_number(opts, "reboot-timeout", -1);
|
|
||||||
|
|
||||||
/* validate the input */
|
/* validate the input */
|
||||||
if (rt_val > 0xffff && rt_val != (uint64_t)-1) {
|
if (rt_val > 0xffff && rt_val != (uint64_t)-1) {
|
||||||
|
@ -1133,7 +1120,7 @@ static void fw_cfg_common_realize(DeviceState *dev, Error **errp)
|
||||||
fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (char *)"QEMU", 4);
|
fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (char *)"QEMU", 4);
|
||||||
fw_cfg_add_bytes(s, FW_CFG_UUID, &qemu_uuid, 16);
|
fw_cfg_add_bytes(s, FW_CFG_UUID, &qemu_uuid, 16);
|
||||||
fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)!machine->enable_graphics);
|
fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)!machine->enable_graphics);
|
||||||
fw_cfg_add_i16(s, FW_CFG_BOOT_MENU, (uint16_t)boot_menu);
|
fw_cfg_add_i16(s, FW_CFG_BOOT_MENU, (uint16_t)(machine->boot_config.has_menu && machine->boot_config.menu));
|
||||||
fw_cfg_bootsplash(s);
|
fw_cfg_bootsplash(s);
|
||||||
fw_cfg_reboot(s);
|
fw_cfg_reboot(s);
|
||||||
|
|
||||||
|
|
|
@ -111,7 +111,7 @@ static void ppc_core99_init(MachineState *machine)
|
||||||
const char *kernel_filename = machine->kernel_filename;
|
const char *kernel_filename = machine->kernel_filename;
|
||||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||||
const char *initrd_filename = machine->initrd_filename;
|
const char *initrd_filename = machine->initrd_filename;
|
||||||
const char *boot_device = machine->boot_order;
|
const char *boot_device = machine->boot_config.order;
|
||||||
Core99MachineState *core99_machine = CORE99_MACHINE(machine);
|
Core99MachineState *core99_machine = CORE99_MACHINE(machine);
|
||||||
PowerPCCPU *cpu = NULL;
|
PowerPCCPU *cpu = NULL;
|
||||||
CPUPPCState *env = NULL;
|
CPUPPCState *env = NULL;
|
||||||
|
|
|
@ -82,7 +82,7 @@ static void ppc_heathrow_init(MachineState *machine)
|
||||||
{
|
{
|
||||||
ram_addr_t ram_size = machine->ram_size;
|
ram_addr_t ram_size = machine->ram_size;
|
||||||
const char *bios_name = machine->firmware ?: PROM_FILENAME;
|
const char *bios_name = machine->firmware ?: PROM_FILENAME;
|
||||||
const char *boot_device = machine->boot_order;
|
const char *boot_device = machine->boot_config.order;
|
||||||
PowerPCCPU *cpu = NULL;
|
PowerPCCPU *cpu = NULL;
|
||||||
CPUPPCState *env = NULL;
|
CPUPPCState *env = NULL;
|
||||||
char *filename;
|
char *filename;
|
||||||
|
|
|
@ -381,7 +381,7 @@ static void ibm_40p_init(MachineState *machine)
|
||||||
}
|
}
|
||||||
boot_device = 'm';
|
boot_device = 'm';
|
||||||
} else {
|
} else {
|
||||||
boot_device = machine->boot_order[0];
|
boot_device = machine->boot_config.order[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)machine->smp.max_cpus);
|
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)machine->smp.max_cpus);
|
||||||
|
|
|
@ -1044,8 +1044,8 @@ static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt, bool reset)
|
||||||
_FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel-le", NULL, 0));
|
_FDT(fdt_setprop(fdt, chosen, "qemu,boot-kernel-le", NULL, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (boot_menu) {
|
if (machine->boot_config.has_menu && machine->boot_config.menu) {
|
||||||
_FDT((fdt_setprop_cell(fdt, chosen, "qemu,boot-menu", boot_menu)));
|
_FDT((fdt_setprop_cell(fdt, chosen, "qemu,boot-menu", true)));
|
||||||
}
|
}
|
||||||
_FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-width", graphic_width));
|
_FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-width", graphic_width));
|
||||||
_FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-height", graphic_height));
|
_FDT(fdt_setprop_cell(fdt, chosen, "qemu,graphic-height", graphic_height));
|
||||||
|
|
|
@ -290,13 +290,10 @@ static Property s390_ipl_properties[] = {
|
||||||
|
|
||||||
static void s390_ipl_set_boot_menu(S390IPLState *ipl)
|
static void s390_ipl_set_boot_menu(S390IPLState *ipl)
|
||||||
{
|
{
|
||||||
QemuOptsList *plist = qemu_find_opts("boot-opts");
|
|
||||||
QemuOpts *opts = QTAILQ_FIRST(&plist->head);
|
|
||||||
const char *tmp;
|
|
||||||
unsigned long splash_time = 0;
|
unsigned long splash_time = 0;
|
||||||
|
|
||||||
if (!get_boot_device(0)) {
|
if (!get_boot_device(0)) {
|
||||||
if (boot_menu) {
|
if (current_machine->boot_config.has_menu && current_machine->boot_config.menu) {
|
||||||
error_report("boot menu requires a bootindex to be specified for "
|
error_report("boot menu requires a bootindex to be specified for "
|
||||||
"the IPL device");
|
"the IPL device");
|
||||||
}
|
}
|
||||||
|
@ -306,7 +303,7 @@ static void s390_ipl_set_boot_menu(S390IPLState *ipl)
|
||||||
switch (ipl->iplb.pbt) {
|
switch (ipl->iplb.pbt) {
|
||||||
case S390_IPL_TYPE_CCW:
|
case S390_IPL_TYPE_CCW:
|
||||||
/* In the absence of -boot menu, use zipl parameters */
|
/* In the absence of -boot menu, use zipl parameters */
|
||||||
if (!qemu_opt_get(opts, "menu")) {
|
if (!current_machine->boot_config.has_menu) {
|
||||||
ipl->qipl.qipl_flags |= QIPL_FLAG_BM_OPTS_ZIPL;
|
ipl->qipl.qipl_flags |= QIPL_FLAG_BM_OPTS_ZIPL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -314,26 +311,21 @@ static void s390_ipl_set_boot_menu(S390IPLState *ipl)
|
||||||
case S390_IPL_TYPE_QEMU_SCSI:
|
case S390_IPL_TYPE_QEMU_SCSI:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (boot_menu) {
|
if (current_machine->boot_config.has_menu && current_machine->boot_config.menu) {
|
||||||
error_report("boot menu is not supported for this device type");
|
error_report("boot menu is not supported for this device type");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!boot_menu) {
|
if (!current_machine->boot_config.has_menu || !current_machine->boot_config.menu) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ipl->qipl.qipl_flags |= QIPL_FLAG_BM_OPTS_CMD;
|
ipl->qipl.qipl_flags |= QIPL_FLAG_BM_OPTS_CMD;
|
||||||
|
|
||||||
tmp = qemu_opt_get(opts, "splash-time");
|
if (current_machine->boot_config.has_splash_time) {
|
||||||
|
splash_time = current_machine->boot_config.splash_time;
|
||||||
if (tmp && qemu_strtoul(tmp, NULL, 10, &splash_time)) {
|
|
||||||
error_report("splash-time is invalid, forcing it to 0");
|
|
||||||
ipl->qipl.boot_menu_timeout = 0;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (splash_time > 0xffffffff) {
|
if (splash_time > 0xffffffff) {
|
||||||
error_report("splash-time is too large, forcing it to max value");
|
error_report("splash-time is too large, forcing it to max value");
|
||||||
ipl->qipl.boot_menu_timeout = 0xffffffff;
|
ipl->qipl.boot_menu_timeout = 0xffffffff;
|
||||||
|
|
|
@ -831,8 +831,7 @@ static void sun4m_hw_init(MachineState *machine)
|
||||||
SysBusDevice *s;
|
SysBusDevice *s;
|
||||||
unsigned int smp_cpus = machine->smp.cpus;
|
unsigned int smp_cpus = machine->smp.cpus;
|
||||||
unsigned int max_cpus = machine->smp.max_cpus;
|
unsigned int max_cpus = machine->smp.max_cpus;
|
||||||
Object *ram_memdev = object_resolve_path_type(machine->ram_memdev_id,
|
HostMemoryBackend *ram_memdev = machine->memdev;
|
||||||
TYPE_MEMORY_BACKEND, NULL);
|
|
||||||
NICInfo *nd = &nd_table[0];
|
NICInfo *nd = &nd_table[0];
|
||||||
|
|
||||||
if (machine->ram_size > hwdef->max_mem) {
|
if (machine->ram_size > hwdef->max_mem) {
|
||||||
|
@ -852,7 +851,7 @@ static void sun4m_hw_init(MachineState *machine)
|
||||||
|
|
||||||
/* Create and map RAM frontend */
|
/* Create and map RAM frontend */
|
||||||
dev = qdev_new("memory");
|
dev = qdev_new("memory");
|
||||||
object_property_set_link(OBJECT(dev), "memdev", ram_memdev, &error_fatal);
|
object_property_set_link(OBJECT(dev), "memdev", OBJECT(ram_memdev), &error_fatal);
|
||||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0);
|
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0);
|
||||||
|
|
||||||
|
@ -1050,7 +1049,7 @@ static void sun4m_hw_init(MachineState *machine)
|
||||||
machine->ram_size, &initrd_size);
|
machine->ram_size, &initrd_size);
|
||||||
|
|
||||||
nvram_init(nvram, (uint8_t *)&nd->macaddr, machine->kernel_cmdline,
|
nvram_init(nvram, (uint8_t *)&nd->macaddr, machine->kernel_cmdline,
|
||||||
machine->boot_order, machine->ram_size, kernel_size,
|
machine->boot_config.order, machine->ram_size, kernel_size,
|
||||||
graphic_width, graphic_height, graphic_depth,
|
graphic_width, graphic_height, graphic_depth,
|
||||||
hwdef->nvram_machine_id, "Sun4m");
|
hwdef->nvram_machine_id, "Sun4m");
|
||||||
|
|
||||||
|
@ -1091,7 +1090,7 @@ static void sun4m_hw_init(MachineState *machine)
|
||||||
}
|
}
|
||||||
fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR);
|
fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR);
|
||||||
fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size);
|
fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size);
|
||||||
fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, machine->boot_order[0]);
|
fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, machine->boot_config.order[0]);
|
||||||
qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
|
qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -695,7 +695,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
|
||||||
&kernel_addr, &kernel_entry);
|
&kernel_addr, &kernel_entry);
|
||||||
|
|
||||||
sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", machine->ram_size,
|
sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", machine->ram_size,
|
||||||
machine->boot_order,
|
machine->boot_config.order,
|
||||||
kernel_addr, kernel_size,
|
kernel_addr, kernel_size,
|
||||||
machine->kernel_cmdline,
|
machine->kernel_cmdline,
|
||||||
initrd_addr, initrd_size,
|
initrd_addr, initrd_size,
|
||||||
|
@ -727,7 +727,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
|
||||||
}
|
}
|
||||||
fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr);
|
fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr);
|
||||||
fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size);
|
fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size);
|
||||||
fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, machine->boot_order[0]);
|
fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, machine->boot_config.order[0]);
|
||||||
|
|
||||||
fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_WIDTH, graphic_width);
|
fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_WIDTH, graphic_width);
|
||||||
fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_HEIGHT, graphic_height);
|
fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_HEIGHT, graphic_height);
|
||||||
|
|
|
@ -203,7 +203,6 @@ static int vhost_kernel_get_vq_index(struct vhost_dev *dev, int idx)
|
||||||
return idx - dev->vq_index;
|
return idx - dev->vq_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_VHOST_VSOCK
|
|
||||||
static int vhost_kernel_vsock_set_guest_cid(struct vhost_dev *dev,
|
static int vhost_kernel_vsock_set_guest_cid(struct vhost_dev *dev,
|
||||||
uint64_t guest_cid)
|
uint64_t guest_cid)
|
||||||
{
|
{
|
||||||
|
@ -214,7 +213,6 @@ static int vhost_kernel_vsock_set_running(struct vhost_dev *dev, int start)
|
||||||
{
|
{
|
||||||
return vhost_kernel_call(dev, VHOST_VSOCK_SET_RUNNING, &start);
|
return vhost_kernel_call(dev, VHOST_VSOCK_SET_RUNNING, &start);
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_VHOST_VSOCK */
|
|
||||||
|
|
||||||
static void vhost_kernel_iotlb_read(void *opaque)
|
static void vhost_kernel_iotlb_read(void *opaque)
|
||||||
{
|
{
|
||||||
|
@ -319,10 +317,8 @@ const VhostOps kernel_ops = {
|
||||||
.vhost_set_owner = vhost_kernel_set_owner,
|
.vhost_set_owner = vhost_kernel_set_owner,
|
||||||
.vhost_reset_device = vhost_kernel_reset_device,
|
.vhost_reset_device = vhost_kernel_reset_device,
|
||||||
.vhost_get_vq_index = vhost_kernel_get_vq_index,
|
.vhost_get_vq_index = vhost_kernel_get_vq_index,
|
||||||
#ifdef CONFIG_VHOST_VSOCK
|
|
||||||
.vhost_vsock_set_guest_cid = vhost_kernel_vsock_set_guest_cid,
|
.vhost_vsock_set_guest_cid = vhost_kernel_vsock_set_guest_cid,
|
||||||
.vhost_vsock_set_running = vhost_kernel_vsock_set_running,
|
.vhost_vsock_set_running = vhost_kernel_vsock_set_running,
|
||||||
#endif /* CONFIG_VHOST_VSOCK */
|
|
||||||
.vhost_set_iotlb_callback = vhost_kernel_set_iotlb_callback,
|
.vhost_set_iotlb_callback = vhost_kernel_set_iotlb_callback,
|
||||||
.vhost_send_device_iotlb_msg = vhost_kernel_send_device_iotlb_msg,
|
.vhost_send_device_iotlb_msg = vhost_kernel_send_device_iotlb_msg,
|
||||||
};
|
};
|
||||||
|
|
|
@ -60,7 +60,6 @@
|
||||||
#include "hw/qdev-properties.h"
|
#include "hw/qdev-properties.h"
|
||||||
#include "hw/qdev-properties-system.h"
|
#include "hw/qdev-properties-system.h"
|
||||||
#include "hw/xen/xen.h"
|
#include "hw/xen/xen.h"
|
||||||
#include "hw/i386/pc.h"
|
|
||||||
#include "hw/xen/xen-legacy-backend.h"
|
#include "hw/xen/xen-legacy-backend.h"
|
||||||
#include "xen_pt.h"
|
#include "xen_pt.h"
|
||||||
#include "qemu/range.h"
|
#include "qemu/range.h"
|
||||||
|
@ -702,17 +701,6 @@ static const MemoryListener xen_pt_io_listener = {
|
||||||
.priority = 10,
|
.priority = 10,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
|
||||||
xen_igd_passthrough_isa_bridge_create(XenPCIPassthroughState *s,
|
|
||||||
XenHostPCIDevice *dev)
|
|
||||||
{
|
|
||||||
uint16_t gpu_dev_id;
|
|
||||||
PCIDevice *d = &s->dev;
|
|
||||||
|
|
||||||
gpu_dev_id = dev->device_id;
|
|
||||||
igd_passthrough_isa_bridge_create(pci_get_bus(d), gpu_dev_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* destroy. */
|
/* destroy. */
|
||||||
static void xen_pt_destroy(PCIDevice *d) {
|
static void xen_pt_destroy(PCIDevice *d) {
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(XenPCIPassthroughState, XEN_PT_DEVICE)
|
||||||
|
|
||||||
uint32_t igd_read_opregion(XenPCIPassthroughState *s);
|
uint32_t igd_read_opregion(XenPCIPassthroughState *s);
|
||||||
void igd_write_opregion(XenPCIPassthroughState *s, uint32_t val);
|
void igd_write_opregion(XenPCIPassthroughState *s, uint32_t val);
|
||||||
|
void xen_igd_passthrough_isa_bridge_create(XenPCIPassthroughState *s,
|
||||||
|
XenHostPCIDevice *dev);
|
||||||
|
|
||||||
/* function type for config reg */
|
/* function type for config reg */
|
||||||
typedef int (*xen_pt_conf_reg_init)
|
typedef int (*xen_pt_conf_reg_init)
|
||||||
|
|
|
@ -289,3 +289,125 @@ void igd_write_opregion(XenPCIPassthroughState *s, uint32_t val)
|
||||||
(unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
|
(unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
|
||||||
(unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT));
|
(unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t gpu_device_id;
|
||||||
|
uint16_t pch_device_id;
|
||||||
|
uint8_t pch_revision_id;
|
||||||
|
} IGDDeviceIDInfo;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In real world different GPU should have different PCH. But actually
|
||||||
|
* the different PCH DIDs likely map to different PCH SKUs. We do the
|
||||||
|
* same thing for the GPU. For PCH, the different SKUs are going to be
|
||||||
|
* all the same silicon design and implementation, just different
|
||||||
|
* features turn on and off with fuses. The SW interfaces should be
|
||||||
|
* consistent across all SKUs in a given family (eg LPT). But just same
|
||||||
|
* features may not be supported.
|
||||||
|
*
|
||||||
|
* Most of these different PCH features probably don't matter to the
|
||||||
|
* Gfx driver, but obviously any difference in display port connections
|
||||||
|
* will so it should be fine with any PCH in case of passthrough.
|
||||||
|
*
|
||||||
|
* So currently use one PCH version, 0x8c4e, to cover all HSW(Haswell)
|
||||||
|
* scenarios, 0x9cc3 for BDW(Broadwell).
|
||||||
|
*/
|
||||||
|
static const IGDDeviceIDInfo igd_combo_id_infos[] = {
|
||||||
|
/* HSW Classic */
|
||||||
|
{0x0402, 0x8c4e, 0x04}, /* HSWGT1D, HSWD_w7 */
|
||||||
|
{0x0406, 0x8c4e, 0x04}, /* HSWGT1M, HSWM_w7 */
|
||||||
|
{0x0412, 0x8c4e, 0x04}, /* HSWGT2D, HSWD_w7 */
|
||||||
|
{0x0416, 0x8c4e, 0x04}, /* HSWGT2M, HSWM_w7 */
|
||||||
|
{0x041E, 0x8c4e, 0x04}, /* HSWGT15D, HSWD_w7 */
|
||||||
|
/* HSW ULT */
|
||||||
|
{0x0A06, 0x8c4e, 0x04}, /* HSWGT1UT, HSWM_w7 */
|
||||||
|
{0x0A16, 0x8c4e, 0x04}, /* HSWGT2UT, HSWM_w7 */
|
||||||
|
{0x0A26, 0x8c4e, 0x06}, /* HSWGT3UT, HSWM_w7 */
|
||||||
|
{0x0A2E, 0x8c4e, 0x04}, /* HSWGT3UT28W, HSWM_w7 */
|
||||||
|
{0x0A1E, 0x8c4e, 0x04}, /* HSWGT2UX, HSWM_w7 */
|
||||||
|
{0x0A0E, 0x8c4e, 0x04}, /* HSWGT1ULX, HSWM_w7 */
|
||||||
|
/* HSW CRW */
|
||||||
|
{0x0D26, 0x8c4e, 0x04}, /* HSWGT3CW, HSWM_w7 */
|
||||||
|
{0x0D22, 0x8c4e, 0x04}, /* HSWGT3CWDT, HSWD_w7 */
|
||||||
|
/* HSW Server */
|
||||||
|
{0x041A, 0x8c4e, 0x04}, /* HSWSVGT2, HSWD_w7 */
|
||||||
|
/* HSW SRVR */
|
||||||
|
{0x040A, 0x8c4e, 0x04}, /* HSWSVGT1, HSWD_w7 */
|
||||||
|
/* BSW */
|
||||||
|
{0x1606, 0x9cc3, 0x03}, /* BDWULTGT1, BDWM_w7 */
|
||||||
|
{0x1616, 0x9cc3, 0x03}, /* BDWULTGT2, BDWM_w7 */
|
||||||
|
{0x1626, 0x9cc3, 0x03}, /* BDWULTGT3, BDWM_w7 */
|
||||||
|
{0x160E, 0x9cc3, 0x03}, /* BDWULXGT1, BDWM_w7 */
|
||||||
|
{0x161E, 0x9cc3, 0x03}, /* BDWULXGT2, BDWM_w7 */
|
||||||
|
{0x1602, 0x9cc3, 0x03}, /* BDWHALOGT1, BDWM_w7 */
|
||||||
|
{0x1612, 0x9cc3, 0x03}, /* BDWHALOGT2, BDWM_w7 */
|
||||||
|
{0x1622, 0x9cc3, 0x03}, /* BDWHALOGT3, BDWM_w7 */
|
||||||
|
{0x162B, 0x9cc3, 0x03}, /* BDWHALO28W, BDWM_w7 */
|
||||||
|
{0x162A, 0x9cc3, 0x03}, /* BDWGT3WRKS, BDWM_w7 */
|
||||||
|
{0x162D, 0x9cc3, 0x03}, /* BDWGT3SRVR, BDWM_w7 */
|
||||||
|
};
|
||||||
|
|
||||||
|
static void isa_bridge_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||||
|
|
||||||
|
dc->desc = "ISA bridge faked to support IGD PT";
|
||||||
|
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
|
||||||
|
k->vendor_id = PCI_VENDOR_ID_INTEL;
|
||||||
|
k->class_id = PCI_CLASS_BRIDGE_ISA;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const TypeInfo isa_bridge_info = {
|
||||||
|
.name = "igd-passthrough-isa-bridge",
|
||||||
|
.parent = TYPE_PCI_DEVICE,
|
||||||
|
.instance_size = sizeof(PCIDevice),
|
||||||
|
.class_init = isa_bridge_class_init,
|
||||||
|
.interfaces = (InterfaceInfo[]) {
|
||||||
|
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
|
||||||
|
{ },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static void pt_graphics_register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&isa_bridge_info);
|
||||||
|
}
|
||||||
|
type_init(pt_graphics_register_types)
|
||||||
|
|
||||||
|
void xen_igd_passthrough_isa_bridge_create(XenPCIPassthroughState *s,
|
||||||
|
XenHostPCIDevice *dev)
|
||||||
|
{
|
||||||
|
PCIBus *bus = pci_get_bus(&s->dev);
|
||||||
|
struct PCIDevice *bridge_dev;
|
||||||
|
int i, num;
|
||||||
|
const uint16_t gpu_dev_id = dev->device_id;
|
||||||
|
uint16_t pch_dev_id = 0xffff;
|
||||||
|
uint8_t pch_rev_id = 0;
|
||||||
|
|
||||||
|
num = ARRAY_SIZE(igd_combo_id_infos);
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
if (gpu_dev_id == igd_combo_id_infos[i].gpu_device_id) {
|
||||||
|
pch_dev_id = igd_combo_id_infos[i].pch_device_id;
|
||||||
|
pch_rev_id = igd_combo_id_infos[i].pch_revision_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pch_dev_id == 0xffff) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Currently IGD drivers always need to access PCH by 1f.0. */
|
||||||
|
bridge_dev = pci_create_simple(bus, PCI_DEVFN(0x1f, 0),
|
||||||
|
"igd-passthrough-isa-bridge");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note that vendor id is always PCI_VENDOR_ID_INTEL.
|
||||||
|
*/
|
||||||
|
if (!bridge_dev) {
|
||||||
|
fprintf(stderr, "set igd-passthrough-isa-bridge failed!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pci_config_set_device_id(bridge_dev->config, pch_dev_id);
|
||||||
|
pci_config_set_revision(bridge_dev->config, pch_rev_id);
|
||||||
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ OBJECT_DECLARE_TYPE(MachineState, MachineClass, MACHINE)
|
||||||
|
|
||||||
extern MachineState *current_machine;
|
extern MachineState *current_machine;
|
||||||
|
|
||||||
void machine_run_board_init(MachineState *machine);
|
void machine_run_board_init(MachineState *machine, const char *mem_path, Error **errp);
|
||||||
bool machine_usb(MachineState *machine);
|
bool machine_usb(MachineState *machine);
|
||||||
int machine_phandle_start(MachineState *machine);
|
int machine_phandle_start(MachineState *machine);
|
||||||
bool machine_dump_guest_core(MachineState *machine);
|
bool machine_dump_guest_core(MachineState *machine);
|
||||||
|
@ -339,7 +339,7 @@ struct MachineState {
|
||||||
bool suppress_vmdesc;
|
bool suppress_vmdesc;
|
||||||
bool enable_graphics;
|
bool enable_graphics;
|
||||||
ConfidentialGuestSupport *cgs;
|
ConfidentialGuestSupport *cgs;
|
||||||
char *ram_memdev_id;
|
HostMemoryBackend *memdev;
|
||||||
/*
|
/*
|
||||||
* convenience alias to ram_memdev_id backend memory region
|
* convenience alias to ram_memdev_id backend memory region
|
||||||
* or to numa container memory region
|
* or to numa container memory region
|
||||||
|
@ -350,8 +350,7 @@ struct MachineState {
|
||||||
ram_addr_t ram_size;
|
ram_addr_t ram_size;
|
||||||
ram_addr_t maxram_size;
|
ram_addr_t maxram_size;
|
||||||
uint64_t ram_slots;
|
uint64_t ram_slots;
|
||||||
const char *boot_order;
|
BootConfiguration boot_config;
|
||||||
const char *boot_once;
|
|
||||||
char *kernel_filename;
|
char *kernel_filename;
|
||||||
char *kernel_cmdline;
|
char *kernel_cmdline;
|
||||||
char *initrd_filename;
|
char *initrd_filename;
|
||||||
|
|
|
@ -315,5 +315,4 @@ extern const size_t pc_compat_1_4_len;
|
||||||
} \
|
} \
|
||||||
type_init(pc_machine_init_##suffix)
|
type_init(pc_machine_init_##suffix)
|
||||||
|
|
||||||
extern void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -208,17 +208,19 @@ void qemu_co_queue_init(CoQueue *queue);
|
||||||
void coroutine_fn qemu_co_queue_wait_impl(CoQueue *queue, QemuLockable *lock);
|
void coroutine_fn qemu_co_queue_wait_impl(CoQueue *queue, QemuLockable *lock);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the next coroutine from the CoQueue, and wake it up.
|
* Removes the next coroutine from the CoQueue, and queue it to run after
|
||||||
|
* the currently-running coroutine yields.
|
||||||
* Returns true if a coroutine was removed, false if the queue is empty.
|
* Returns true if a coroutine was removed, false if the queue is empty.
|
||||||
* OK to run from coroutine and non-coroutine context.
|
* Used from coroutine context, use qemu_co_enter_next outside.
|
||||||
*/
|
*/
|
||||||
bool qemu_co_queue_next(CoQueue *queue);
|
bool coroutine_fn qemu_co_queue_next(CoQueue *queue);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Empties the CoQueue; all coroutines are woken up.
|
* Empties the CoQueue and queues the coroutine to run after
|
||||||
* OK to run from coroutine and non-coroutine context.
|
* the currently-running coroutine yields.
|
||||||
|
* Used from coroutine context, use qemu_co_enter_all outside.
|
||||||
*/
|
*/
|
||||||
void qemu_co_queue_restart_all(CoQueue *queue);
|
void coroutine_fn qemu_co_queue_restart_all(CoQueue *queue);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the next coroutine from the CoQueue, and wake it up. Unlike
|
* Removes the next coroutine from the CoQueue, and wake it up. Unlike
|
||||||
|
@ -233,6 +235,19 @@ void qemu_co_queue_restart_all(CoQueue *queue);
|
||||||
qemu_co_enter_next_impl(queue, QEMU_MAKE_LOCKABLE(lock))
|
qemu_co_enter_next_impl(queue, QEMU_MAKE_LOCKABLE(lock))
|
||||||
bool qemu_co_enter_next_impl(CoQueue *queue, QemuLockable *lock);
|
bool qemu_co_enter_next_impl(CoQueue *queue, QemuLockable *lock);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Empties the CoQueue, waking the waiting coroutine one at a time. Unlike
|
||||||
|
* qemu_co_queue_all, this function releases the lock during aio_co_wake
|
||||||
|
* because it is meant to be used outside coroutine context; in that case, the
|
||||||
|
* coroutine is entered immediately, before qemu_co_enter_all returns.
|
||||||
|
*
|
||||||
|
* If used in coroutine context, qemu_co_enter_all is equivalent to
|
||||||
|
* qemu_co_queue_all.
|
||||||
|
*/
|
||||||
|
#define qemu_co_enter_all(queue, lock) \
|
||||||
|
qemu_co_enter_all_impl(queue, QEMU_MAKE_LOCKABLE(lock))
|
||||||
|
void qemu_co_enter_all_impl(CoQueue *queue, QemuLockable *lock);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the CoQueue is empty.
|
* Checks if the CoQueue is empty.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -46,8 +46,6 @@ extern int alt_grab;
|
||||||
extern int ctrl_grab;
|
extern int ctrl_grab;
|
||||||
extern int graphic_rotate;
|
extern int graphic_rotate;
|
||||||
extern int old_param;
|
extern int old_param;
|
||||||
extern int boot_menu;
|
|
||||||
extern bool boot_strict;
|
|
||||||
extern uint8_t *boot_splash_filedata;
|
extern uint8_t *boot_splash_filedata;
|
||||||
extern bool enable_mlock;
|
extern bool enable_mlock;
|
||||||
extern bool enable_cpu_pm;
|
extern bool enable_cpu_pm;
|
||||||
|
|
38
meson.build
38
meson.build
|
@ -2179,7 +2179,8 @@ config_host_data.set('CONFIG_AVX512F_OPT', get_option('avx512f') \
|
||||||
|
|
||||||
have_pvrdma = get_option('pvrdma') \
|
have_pvrdma = get_option('pvrdma') \
|
||||||
.require(rdma.found(), error_message: 'PVRDMA requires OpenFabrics libraries') \
|
.require(rdma.found(), error_message: 'PVRDMA requires OpenFabrics libraries') \
|
||||||
.require(cc.compiles('''
|
.require(cc.compiles(gnu_source_prefix + '''
|
||||||
|
#include <sys/mman.h>
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
char buf = 0;
|
char buf = 0;
|
||||||
|
@ -2190,7 +2191,7 @@ have_pvrdma = get_option('pvrdma') \
|
||||||
}'''), error_message: 'PVRDMA requires mremap').allowed()
|
}'''), error_message: 'PVRDMA requires mremap').allowed()
|
||||||
|
|
||||||
if have_pvrdma
|
if have_pvrdma
|
||||||
config_host_data.set('LEGACY_RDMA_REG_MR', not cc.compiles('''
|
config_host_data.set('LEGACY_RDMA_REG_MR', not cc.links('''
|
||||||
#include <infiniband/verbs.h>
|
#include <infiniband/verbs.h>
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
|
@ -2636,10 +2637,25 @@ if have_system
|
||||||
slirp_opt = get_option('slirp')
|
slirp_opt = get_option('slirp')
|
||||||
if slirp_opt in ['enabled', 'auto', 'system']
|
if slirp_opt in ['enabled', 'auto', 'system']
|
||||||
have_internal = fs.exists(meson.current_source_dir() / 'slirp/meson.build')
|
have_internal = fs.exists(meson.current_source_dir() / 'slirp/meson.build')
|
||||||
|
slirp_dep_required = (slirp_opt == 'system' or
|
||||||
|
slirp_opt == 'enabled' and not have_internal)
|
||||||
slirp = dependency('slirp', kwargs: static_kwargs,
|
slirp = dependency('slirp', kwargs: static_kwargs,
|
||||||
method: 'pkg-config',
|
method: 'pkg-config', version: '>=4.1.0',
|
||||||
required: slirp_opt == 'system' or
|
required: slirp_dep_required)
|
||||||
slirp_opt == 'enabled' and not have_internal)
|
# slirp <4.7 is incompatible with CFI support in QEMU. This is because
|
||||||
|
# it passes function pointers within libslirp as callbacks for timers.
|
||||||
|
# When using a system-wide shared libslirp, the type information for the
|
||||||
|
# callback is missing and the timer call produces a false positive with CFI.
|
||||||
|
# Do not use the "version" keyword argument to produce a better error.
|
||||||
|
# with control-flow integrity.
|
||||||
|
if get_option('cfi') and slirp.found() and slirp.version().version_compare('<4.7')
|
||||||
|
if slirp_dep_required
|
||||||
|
error('Control-Flow Integrity requires libslirp 4.7.')
|
||||||
|
else
|
||||||
|
warning('Control-Flow Integrity requires libslirp 4.7, not using system-wide libslirp.')
|
||||||
|
slirp = not_found
|
||||||
|
endif
|
||||||
|
endif
|
||||||
if slirp.found()
|
if slirp.found()
|
||||||
slirp_opt = 'system'
|
slirp_opt = 'system'
|
||||||
elif have_internal
|
elif have_internal
|
||||||
|
@ -2712,18 +2728,6 @@ if have_system
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# For CFI, we need to compile slirp as a static library together with qemu.
|
|
||||||
# This is because we register slirp functions as callbacks for QEMU Timers.
|
|
||||||
# When using a system-wide shared libslirp, the type information for the
|
|
||||||
# callback is missing and the timer call produces a false positive with CFI.
|
|
||||||
#
|
|
||||||
# Now that slirp_opt has been defined, check if the selected slirp is compatible
|
|
||||||
# with control-flow integrity.
|
|
||||||
if get_option('cfi') and slirp_opt == 'system'
|
|
||||||
error('Control-Flow Integrity is not compatible with system-wide slirp.' \
|
|
||||||
+ ' Please configure with --enable-slirp=git')
|
|
||||||
endif
|
|
||||||
|
|
||||||
fdt = not_found
|
fdt = not_found
|
||||||
if have_system
|
if have_system
|
||||||
fdt_opt = get_option('fdt')
|
fdt_opt = get_option('fdt')
|
||||||
|
|
85
net/slirp.c
85
net/slirp.c
|
@ -184,23 +184,66 @@ static int64_t net_slirp_clock_get_ns(void *opaque)
|
||||||
return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct SlirpTimer SlirpTimer;
|
||||||
|
struct SlirpTimer {
|
||||||
|
QEMUTimer timer;
|
||||||
|
#if SLIRP_CHECK_VERSION(4,7,0)
|
||||||
|
Slirp *slirp;
|
||||||
|
SlirpTimerId id;
|
||||||
|
void *cb_opaque;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#if SLIRP_CHECK_VERSION(4,7,0)
|
||||||
|
static void net_slirp_init_completed(Slirp *slirp, void *opaque)
|
||||||
|
{
|
||||||
|
SlirpState *s = opaque;
|
||||||
|
s->slirp = slirp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void net_slirp_timer_cb(void *opaque)
|
||||||
|
{
|
||||||
|
SlirpTimer *t = opaque;
|
||||||
|
slirp_handle_timer(t->slirp, t->id, t->cb_opaque);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *net_slirp_timer_new_opaque(SlirpTimerId id,
|
||||||
|
void *cb_opaque, void *opaque)
|
||||||
|
{
|
||||||
|
SlirpState *s = opaque;
|
||||||
|
SlirpTimer *t = g_new(SlirpTimer, 1);
|
||||||
|
t->slirp = s->slirp;
|
||||||
|
t->id = id;
|
||||||
|
t->cb_opaque = cb_opaque;
|
||||||
|
timer_init_full(&t->timer, NULL, QEMU_CLOCK_VIRTUAL,
|
||||||
|
SCALE_MS, QEMU_TIMER_ATTR_EXTERNAL,
|
||||||
|
net_slirp_timer_cb, t);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
#else
|
||||||
static void *net_slirp_timer_new(SlirpTimerCb cb,
|
static void *net_slirp_timer_new(SlirpTimerCb cb,
|
||||||
void *cb_opaque, void *opaque)
|
void *cb_opaque, void *opaque)
|
||||||
{
|
{
|
||||||
return timer_new_full(NULL, QEMU_CLOCK_VIRTUAL,
|
SlirpTimer *t = g_new(SlirpTimer, 1);
|
||||||
SCALE_MS, QEMU_TIMER_ATTR_EXTERNAL,
|
timer_init_full(&t->timer, NULL, QEMU_CLOCK_VIRTUAL,
|
||||||
cb, cb_opaque);
|
SCALE_MS, QEMU_TIMER_ATTR_EXTERNAL,
|
||||||
|
cb, cb_opaque);
|
||||||
|
return t;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void net_slirp_timer_free(void *timer, void *opaque)
|
static void net_slirp_timer_free(void *timer, void *opaque)
|
||||||
{
|
{
|
||||||
timer_free(timer);
|
SlirpTimer *t = timer;
|
||||||
|
timer_del(&t->timer);
|
||||||
|
g_free(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void net_slirp_timer_mod(void *timer, int64_t expire_timer,
|
static void net_slirp_timer_mod(void *timer, int64_t expire_timer,
|
||||||
void *opaque)
|
void *opaque)
|
||||||
{
|
{
|
||||||
timer_mod(timer, expire_timer);
|
SlirpTimer *t = timer;
|
||||||
|
timer_mod(&t->timer, expire_timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void net_slirp_register_poll_fd(int fd, void *opaque)
|
static void net_slirp_register_poll_fd(int fd, void *opaque)
|
||||||
|
@ -222,7 +265,12 @@ static const SlirpCb slirp_cb = {
|
||||||
.send_packet = net_slirp_send_packet,
|
.send_packet = net_slirp_send_packet,
|
||||||
.guest_error = net_slirp_guest_error,
|
.guest_error = net_slirp_guest_error,
|
||||||
.clock_get_ns = net_slirp_clock_get_ns,
|
.clock_get_ns = net_slirp_clock_get_ns,
|
||||||
|
#if SLIRP_CHECK_VERSION(4,7,0)
|
||||||
|
.init_completed = net_slirp_init_completed,
|
||||||
|
.timer_new_opaque = net_slirp_timer_new_opaque,
|
||||||
|
#else
|
||||||
.timer_new = net_slirp_timer_new,
|
.timer_new = net_slirp_timer_new,
|
||||||
|
#endif
|
||||||
.timer_free = net_slirp_timer_free,
|
.timer_free = net_slirp_timer_free,
|
||||||
.timer_mod = net_slirp_timer_mod,
|
.timer_mod = net_slirp_timer_mod,
|
||||||
.register_poll_fd = net_slirp_register_poll_fd,
|
.register_poll_fd = net_slirp_register_poll_fd,
|
||||||
|
@ -380,6 +428,7 @@ static int net_slirp_init(NetClientState *peer, const char *model,
|
||||||
#if defined(CONFIG_SMBD_COMMAND)
|
#if defined(CONFIG_SMBD_COMMAND)
|
||||||
struct in_addr smbsrv = { .s_addr = 0 };
|
struct in_addr smbsrv = { .s_addr = 0 };
|
||||||
#endif
|
#endif
|
||||||
|
SlirpConfig cfg = { 0 };
|
||||||
NetClientState *nc;
|
NetClientState *nc;
|
||||||
SlirpState *s;
|
SlirpState *s;
|
||||||
char buf[20];
|
char buf[20];
|
||||||
|
@ -568,12 +617,26 @@ static int net_slirp_init(NetClientState *peer, const char *model,
|
||||||
|
|
||||||
s = DO_UPCAST(SlirpState, nc, nc);
|
s = DO_UPCAST(SlirpState, nc, nc);
|
||||||
|
|
||||||
s->slirp = slirp_init(restricted, ipv4, net, mask, host,
|
cfg.version = SLIRP_CHECK_VERSION(4,7,0) ? 4 : 1;
|
||||||
ipv6, ip6_prefix, vprefix6_len, ip6_host,
|
cfg.restricted = restricted;
|
||||||
vhostname, tftp_server_name,
|
cfg.in_enabled = ipv4;
|
||||||
tftp_export, bootfile, dhcp,
|
cfg.vnetwork = net;
|
||||||
dns, ip6_dns, dnssearch, vdomainname,
|
cfg.vnetmask = mask;
|
||||||
&slirp_cb, s);
|
cfg.vhost = host;
|
||||||
|
cfg.in6_enabled = ipv6;
|
||||||
|
cfg.vprefix_addr6 = ip6_prefix;
|
||||||
|
cfg.vprefix_len = vprefix6_len;
|
||||||
|
cfg.vhost6 = ip6_host;
|
||||||
|
cfg.vhostname = vhostname;
|
||||||
|
cfg.tftp_server_name = tftp_server_name;
|
||||||
|
cfg.tftp_path = tftp_export;
|
||||||
|
cfg.bootfile = bootfile;
|
||||||
|
cfg.vdhcp_start = dhcp;
|
||||||
|
cfg.vnameserver = dns;
|
||||||
|
cfg.vnameserver6 = ip6_dns;
|
||||||
|
cfg.vdnssearch = dnssearch;
|
||||||
|
cfg.vdomainname = vdomainname;
|
||||||
|
s->slirp = slirp_new(&cfg, &slirp_cb, s);
|
||||||
QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry);
|
QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -22,9 +22,11 @@ override CFLAGS += $(call cc-option, -fcf-protection=none)
|
||||||
override CPPFLAGS += -MMD -MP -MT $@ -MF $(@D)/$(*F).d
|
override CPPFLAGS += -MMD -MP -MT $@ -MF $(@D)/$(*F).d
|
||||||
|
|
||||||
override CFLAGS += $(filter -W%, $(QEMU_CFLAGS))
|
override CFLAGS += $(filter -W%, $(QEMU_CFLAGS))
|
||||||
override CFLAGS += $(CFLAGS_NOPIE) -ffreestanding -I$(TOPSRC_DIR)/include
|
override CFLAGS += $(call cc-option, -fno-pie)
|
||||||
|
override CFLAGS += -ffreestanding -I$(TOPSRC_DIR)/include
|
||||||
override CFLAGS += $(call cc-option, -fno-stack-protector)
|
override CFLAGS += $(call cc-option, -fno-stack-protector)
|
||||||
override CFLAGS += $(call cc-option, -m16)
|
override CFLAGS += $(call cc-option, -m16)
|
||||||
|
override CFLAGS += $(call cc-option, -Wno-array-bounds)
|
||||||
|
|
||||||
ifeq ($(filter -m16, $(CFLAGS)),)
|
ifeq ($(filter -m16, $(CFLAGS)),)
|
||||||
# Attempt to work around compilers that lack -m16 (GCC <= 4.8, clang <= ??)
|
# Attempt to work around compilers that lack -m16 (GCC <= 4.8, clang <= ??)
|
||||||
|
|
|
@ -1395,6 +1395,36 @@
|
||||||
'data': { 'device': 'str', 'msg': 'str' },
|
'data': { 'device': 'str', 'msg': 'str' },
|
||||||
'features': ['deprecated'] }
|
'features': ['deprecated'] }
|
||||||
|
|
||||||
|
##
|
||||||
|
# @BootConfiguration:
|
||||||
|
#
|
||||||
|
# Schema for virtual machine boot configuration.
|
||||||
|
#
|
||||||
|
# @order: Boot order (a=floppy, c=hard disk, d=CD-ROM, n=network)
|
||||||
|
#
|
||||||
|
# @once: Boot order to apply on first boot
|
||||||
|
#
|
||||||
|
# @menu: Whether to show a boot menu
|
||||||
|
#
|
||||||
|
# @splash: The name of the file to be passed to the firmware as logo picture, if @menu is true.
|
||||||
|
#
|
||||||
|
# @splash-time: How long to show the logo picture, in milliseconds
|
||||||
|
#
|
||||||
|
# @reboot-timeout: Timeout before guest reboots after boot fails
|
||||||
|
#
|
||||||
|
# @strict: Whether to attempt booting from devices not included in the boot order
|
||||||
|
#
|
||||||
|
# Since: 7.1
|
||||||
|
##
|
||||||
|
{ 'struct': 'BootConfiguration', 'data': {
|
||||||
|
'*order': 'str',
|
||||||
|
'*once': 'str',
|
||||||
|
'*menu': 'bool',
|
||||||
|
'*splash': 'str',
|
||||||
|
'*splash-time': 'int',
|
||||||
|
'*reboot-timeout': 'int',
|
||||||
|
'*strict': 'bool' } }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @SMPConfiguration:
|
# @SMPConfiguration:
|
||||||
#
|
#
|
||||||
|
@ -1584,3 +1614,21 @@
|
||||||
##
|
##
|
||||||
{ 'enum': 'SmbiosEntryPointType',
|
{ 'enum': 'SmbiosEntryPointType',
|
||||||
'data': [ '32', '64' ] }
|
'data': [ '32', '64' ] }
|
||||||
|
|
||||||
|
##
|
||||||
|
# @MemorySizeConfiguration:
|
||||||
|
#
|
||||||
|
# Schema for memory size configuration.
|
||||||
|
#
|
||||||
|
# @size: memory size in bytes
|
||||||
|
#
|
||||||
|
# @max-size: maximum hotpluggable memory size in bytes
|
||||||
|
#
|
||||||
|
# @slots: number of available memory slots for hotplug
|
||||||
|
#
|
||||||
|
# Since: 7.1
|
||||||
|
##
|
||||||
|
{ 'struct': 'MemorySizeConfiguration', 'data': {
|
||||||
|
'*size': 'size',
|
||||||
|
'*max-size': 'size',
|
||||||
|
'*slots': 'uint64' } }
|
||||||
|
|
|
@ -2831,8 +2831,8 @@ sub process {
|
||||||
}
|
}
|
||||||
|
|
||||||
# check for pointless casting of g_malloc return
|
# check for pointless casting of g_malloc return
|
||||||
if ($line =~ /\*\s*\)\s*g_(try)?(m|re)alloc(0?)(_n)?\b/) {
|
if ($line =~ /\*\s*\)\s*g_(try|)(m|re)alloc(0?)(_n)?\b/) {
|
||||||
if ($2 == 'm') {
|
if ($2 eq 'm') {
|
||||||
ERROR("unnecessary cast may hide bugs, use g_$1new$3 instead\n" . $herecurr);
|
ERROR("unnecessary cast may hide bugs, use g_$1new$3 instead\n" . $herecurr);
|
||||||
} else {
|
} else {
|
||||||
ERROR("unnecessary cast may hide bugs, use g_$1renew$3 instead\n" . $herecurr);
|
ERROR("unnecessary cast may hide bugs, use g_$1renew$3 instead\n" . $herecurr);
|
||||||
|
|
|
@ -23,6 +23,7 @@ MSR_IA32_VMX_TRUE_PROCBASED_CTLS = 0x48E
|
||||||
MSR_IA32_VMX_TRUE_EXIT_CTLS = 0x48F
|
MSR_IA32_VMX_TRUE_EXIT_CTLS = 0x48F
|
||||||
MSR_IA32_VMX_TRUE_ENTRY_CTLS = 0x490
|
MSR_IA32_VMX_TRUE_ENTRY_CTLS = 0x490
|
||||||
MSR_IA32_VMX_VMFUNC = 0x491
|
MSR_IA32_VMX_VMFUNC = 0x491
|
||||||
|
MSR_IA32_VMX_PROCBASED_CTLS3 = 0x492
|
||||||
|
|
||||||
class msr(object):
|
class msr(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -71,6 +72,13 @@ class Control(object):
|
||||||
s = 'yes'
|
s = 'yes'
|
||||||
print(' %-40s %s' % (self.bits[bit], s))
|
print(' %-40s %s' % (self.bits[bit], s))
|
||||||
|
|
||||||
|
# All 64 bits in the tertiary controls MSR are allowed-1
|
||||||
|
class Allowed1Control(Control):
|
||||||
|
def read2(self, nr):
|
||||||
|
m = msr()
|
||||||
|
val = m.read(nr, 0)
|
||||||
|
return (0, val)
|
||||||
|
|
||||||
class Misc(object):
|
class Misc(object):
|
||||||
def __init__(self, name, bits, msr):
|
def __init__(self, name, bits, msr):
|
||||||
self.name = name
|
self.name = name
|
||||||
|
@ -135,6 +143,7 @@ controls = [
|
||||||
12: 'RDTSC exiting',
|
12: 'RDTSC exiting',
|
||||||
15: 'CR3-load exiting',
|
15: 'CR3-load exiting',
|
||||||
16: 'CR3-store exiting',
|
16: 'CR3-store exiting',
|
||||||
|
17: 'Activate tertiary controls',
|
||||||
19: 'CR8-load exiting',
|
19: 'CR8-load exiting',
|
||||||
20: 'CR8-store exiting',
|
20: 'CR8-store exiting',
|
||||||
21: 'Use TPR shadow',
|
21: 'Use TPR shadow',
|
||||||
|
@ -186,6 +195,14 @@ controls = [
|
||||||
cap_msr = MSR_IA32_VMX_PROCBASED_CTLS2,
|
cap_msr = MSR_IA32_VMX_PROCBASED_CTLS2,
|
||||||
),
|
),
|
||||||
|
|
||||||
|
Allowed1Control(
|
||||||
|
name = 'tertiary processor-based controls',
|
||||||
|
bits = {
|
||||||
|
4: 'Enable IPI virtualization'
|
||||||
|
},
|
||||||
|
cap_msr = MSR_IA32_VMX_PROCBASED_CTLS3,
|
||||||
|
),
|
||||||
|
|
||||||
Control(
|
Control(
|
||||||
name = 'VM-Exit controls',
|
name = 'VM-Exit controls',
|
||||||
bits = {
|
bits = {
|
||||||
|
|
2
slirp
2
slirp
|
@ -1 +1 @@
|
||||||
Subproject commit a88d9ace234a24ce1c17189642ef9104799425e0
|
Subproject commit 9d59bb775d6294c8b447a88512f7bb43f12a25a8
|
|
@ -268,7 +268,8 @@ char *get_boot_devices_list(size_t *size)
|
||||||
|
|
||||||
*size = total;
|
*size = total;
|
||||||
|
|
||||||
if (boot_strict && *size > 0) {
|
if (current_machine->boot_config.has_strict &&
|
||||||
|
current_machine->boot_config.strict && *size > 0) {
|
||||||
list[total-1] = '\n';
|
list[total-1] = '\n';
|
||||||
list = g_realloc(list, total + 5);
|
list = g_realloc(list, total + 5);
|
||||||
memcpy(&list[total], "HALT", 5);
|
memcpy(&list[total], "HALT", 5);
|
||||||
|
|
|
@ -54,8 +54,6 @@ int alt_grab;
|
||||||
int ctrl_grab;
|
int ctrl_grab;
|
||||||
unsigned int nb_prom_envs;
|
unsigned int nb_prom_envs;
|
||||||
const char *prom_envs[MAX_PROM_ENVS];
|
const char *prom_envs[MAX_PROM_ENVS];
|
||||||
int boot_menu;
|
|
||||||
bool boot_strict;
|
|
||||||
uint8_t *boot_splash_filedata;
|
uint8_t *boot_splash_filedata;
|
||||||
int only_migratable; /* turn it off unless user states otherwise */
|
int only_migratable; /* turn it off unless user states otherwise */
|
||||||
int icount_align_option;
|
int icount_align_option;
|
||||||
|
|
231
softmmu/vl.c
231
softmmu/vl.c
|
@ -159,11 +159,11 @@ static const char *mem_path;
|
||||||
static const char *incoming;
|
static const char *incoming;
|
||||||
static const char *loadvm;
|
static const char *loadvm;
|
||||||
static const char *accelerators;
|
static const char *accelerators;
|
||||||
|
static bool have_custom_ram_size;
|
||||||
|
static const char *ram_memdev_id;
|
||||||
static QDict *machine_opts_dict;
|
static QDict *machine_opts_dict;
|
||||||
static QTAILQ_HEAD(, ObjectOption) object_opts = QTAILQ_HEAD_INITIALIZER(object_opts);
|
static QTAILQ_HEAD(, ObjectOption) object_opts = QTAILQ_HEAD_INITIALIZER(object_opts);
|
||||||
static QTAILQ_HEAD(, DeviceOption) device_opts = QTAILQ_HEAD_INITIALIZER(device_opts);
|
static QTAILQ_HEAD(, DeviceOption) device_opts = QTAILQ_HEAD_INITIALIZER(device_opts);
|
||||||
static ram_addr_t maxram_size;
|
|
||||||
static uint64_t ram_slots;
|
|
||||||
static int display_remote;
|
static int display_remote;
|
||||||
static int snapshot;
|
static int snapshot;
|
||||||
static bool preconfig_requested;
|
static bool preconfig_requested;
|
||||||
|
@ -171,7 +171,6 @@ static QemuPluginList plugin_list = QTAILQ_HEAD_INITIALIZER(plugin_list);
|
||||||
static BlockdevOptionsQueue bdo_queue = QSIMPLEQ_HEAD_INITIALIZER(bdo_queue);
|
static BlockdevOptionsQueue bdo_queue = QSIMPLEQ_HEAD_INITIALIZER(bdo_queue);
|
||||||
static bool nographic = false;
|
static bool nographic = false;
|
||||||
static int mem_prealloc; /* force preallocation of physical target memory */
|
static int mem_prealloc; /* force preallocation of physical target memory */
|
||||||
static ram_addr_t ram_size;
|
|
||||||
static const char *vga_model = NULL;
|
static const char *vga_model = NULL;
|
||||||
static DisplayOptions dpy;
|
static DisplayOptions dpy;
|
||||||
static int num_serial_hds;
|
static int num_serial_hds;
|
||||||
|
@ -1736,6 +1735,7 @@ static void keyval_dashify(QDict *qdict, Error **errp)
|
||||||
static void qemu_apply_legacy_machine_options(QDict *qdict)
|
static void qemu_apply_legacy_machine_options(QDict *qdict)
|
||||||
{
|
{
|
||||||
const char *value;
|
const char *value;
|
||||||
|
QObject *prop;
|
||||||
|
|
||||||
keyval_dashify(qdict, &error_fatal);
|
keyval_dashify(qdict, &error_fatal);
|
||||||
|
|
||||||
|
@ -1768,6 +1768,26 @@ static void qemu_apply_legacy_machine_options(QDict *qdict)
|
||||||
false);
|
false);
|
||||||
qdict_del(qdict, "kernel-irqchip");
|
qdict_del(qdict, "kernel-irqchip");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
value = qdict_get_try_str(qdict, "memory-backend");
|
||||||
|
if (value) {
|
||||||
|
if (mem_path) {
|
||||||
|
error_report("'-mem-path' can't be used together with"
|
||||||
|
"'-machine memory-backend'");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Resolved later. */
|
||||||
|
ram_memdev_id = g_strdup(value);
|
||||||
|
qdict_del(qdict, "memory-backend");
|
||||||
|
}
|
||||||
|
|
||||||
|
prop = qdict_get(qdict, "memory");
|
||||||
|
if (prop) {
|
||||||
|
have_custom_ram_size =
|
||||||
|
qobject_type(prop) == QTYPE_QDICT &&
|
||||||
|
qdict_haskey(qobject_to(QDict, prop), "size");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void object_option_foreach_add(bool (*type_opt_predicate)(const char *))
|
static void object_option_foreach_add(bool (*type_opt_predicate)(const char *))
|
||||||
|
@ -1884,38 +1904,7 @@ static bool object_create_early(const char *type)
|
||||||
|
|
||||||
static void qemu_apply_machine_options(QDict *qdict)
|
static void qemu_apply_machine_options(QDict *qdict)
|
||||||
{
|
{
|
||||||
MachineClass *machine_class = MACHINE_GET_CLASS(current_machine);
|
|
||||||
const char *boot_order = NULL;
|
|
||||||
const char *boot_once = NULL;
|
|
||||||
QemuOpts *opts;
|
|
||||||
|
|
||||||
object_set_properties_from_keyval(OBJECT(current_machine), qdict, false, &error_fatal);
|
object_set_properties_from_keyval(OBJECT(current_machine), qdict, false, &error_fatal);
|
||||||
current_machine->ram_size = ram_size;
|
|
||||||
current_machine->maxram_size = maxram_size;
|
|
||||||
current_machine->ram_slots = ram_slots;
|
|
||||||
|
|
||||||
opts = qemu_opts_find(qemu_find_opts("boot-opts"), NULL);
|
|
||||||
if (opts) {
|
|
||||||
boot_order = qemu_opt_get(opts, "order");
|
|
||||||
if (boot_order) {
|
|
||||||
validate_bootdevices(boot_order, &error_fatal);
|
|
||||||
}
|
|
||||||
|
|
||||||
boot_once = qemu_opt_get(opts, "once");
|
|
||||||
if (boot_once) {
|
|
||||||
validate_bootdevices(boot_once, &error_fatal);
|
|
||||||
}
|
|
||||||
|
|
||||||
boot_menu = qemu_opt_get_bool(opts, "menu", boot_menu);
|
|
||||||
boot_strict = qemu_opt_get_bool(opts, "strict", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!boot_order) {
|
|
||||||
boot_order = machine_class->default_boot_order;
|
|
||||||
}
|
|
||||||
|
|
||||||
current_machine->boot_order = boot_order;
|
|
||||||
current_machine->boot_once = boot_once;
|
|
||||||
|
|
||||||
if (semihosting_enabled() && !semihosting_get_argc()) {
|
if (semihosting_enabled() && !semihosting_get_argc()) {
|
||||||
/* fall back to the -kernel/-append */
|
/* fall back to the -kernel/-append */
|
||||||
|
@ -2026,125 +2015,67 @@ static void qemu_create_late_backends(void)
|
||||||
qemu_semihosting_console_init();
|
qemu_semihosting_console_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool have_custom_ram_size(void)
|
|
||||||
{
|
|
||||||
QemuOpts *opts = qemu_find_opts_singleton("memory");
|
|
||||||
return !!qemu_opt_get_size(opts, "size", 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void qemu_resolve_machine_memdev(void)
|
static void qemu_resolve_machine_memdev(void)
|
||||||
{
|
{
|
||||||
if (current_machine->ram_memdev_id) {
|
if (ram_memdev_id) {
|
||||||
Object *backend;
|
Object *backend;
|
||||||
ram_addr_t backend_size;
|
ram_addr_t backend_size;
|
||||||
|
|
||||||
backend = object_resolve_path_type(current_machine->ram_memdev_id,
|
backend = object_resolve_path_type(ram_memdev_id,
|
||||||
TYPE_MEMORY_BACKEND, NULL);
|
TYPE_MEMORY_BACKEND, NULL);
|
||||||
if (!backend) {
|
if (!backend) {
|
||||||
error_report("Memory backend '%s' not found",
|
error_report("Memory backend '%s' not found", ram_memdev_id);
|
||||||
current_machine->ram_memdev_id);
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
backend_size = object_property_get_uint(backend, "size", &error_abort);
|
if (!have_custom_ram_size) {
|
||||||
if (have_custom_ram_size() && backend_size != ram_size) {
|
backend_size = object_property_get_uint(backend, "size", &error_abort);
|
||||||
error_report("Size specified by -m option must match size of "
|
current_machine->ram_size = backend_size;
|
||||||
"explicitly specified 'memory-backend' property");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
if (mem_path) {
|
|
||||||
error_report("'-mem-path' can't be used together with"
|
|
||||||
"'-machine memory-backend'");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
ram_size = backend_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!xen_enabled()) {
|
|
||||||
/* On 32-bit hosts, QEMU is limited by virtual address space */
|
|
||||||
if (ram_size > (2047 << 20) && HOST_LONG_BITS == 32) {
|
|
||||||
error_report("at most 2047 MB RAM can be simulated");
|
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
|
object_property_set_link(OBJECT(current_machine),
|
||||||
|
"memory-backend", backend, &error_fatal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_memory_options(MachineClass *mc)
|
static void parse_memory_options(const char *arg)
|
||||||
{
|
{
|
||||||
uint64_t sz;
|
QemuOpts *opts;
|
||||||
|
QDict *dict, *prop;
|
||||||
const char *mem_str;
|
const char *mem_str;
|
||||||
const ram_addr_t default_ram_size = mc->default_ram_size;
|
|
||||||
QemuOpts *opts = qemu_find_opts_singleton("memory");
|
|
||||||
Location loc;
|
|
||||||
|
|
||||||
loc_push_none(&loc);
|
opts = qemu_opts_parse_noisily(qemu_find_opts("memory"), arg, true);
|
||||||
qemu_opts_loc_restore(opts);
|
if (!opts) {
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
sz = 0;
|
prop = qdict_new();
|
||||||
mem_str = qemu_opt_get(opts, "size");
|
|
||||||
if (mem_str) {
|
if (qemu_opt_get_size(opts, "size", 0) != 0) {
|
||||||
|
mem_str = qemu_opt_get(opts, "size");
|
||||||
if (!*mem_str) {
|
if (!*mem_str) {
|
||||||
error_report("missing 'size' option value");
|
error_report("missing 'size' option value");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
sz = qemu_opt_get_size(opts, "size", ram_size);
|
|
||||||
|
|
||||||
/* Fix up legacy suffix-less format */
|
/* Fix up legacy suffix-less format */
|
||||||
if (g_ascii_isdigit(mem_str[strlen(mem_str) - 1])) {
|
if (g_ascii_isdigit(mem_str[strlen(mem_str) - 1])) {
|
||||||
uint64_t overflow_check = sz;
|
g_autofree char *mib_str = g_strdup_printf("%sM", mem_str);
|
||||||
|
qdict_put_str(prop, "size", mib_str);
|
||||||
sz *= MiB;
|
} else {
|
||||||
if (sz / MiB != overflow_check) {
|
qdict_put_str(prop, "size", mem_str);
|
||||||
error_report("too large 'size' option value");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* backward compatibility behaviour for case "-m 0" */
|
|
||||||
if (sz == 0) {
|
|
||||||
sz = default_ram_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
sz = QEMU_ALIGN_UP(sz, 8192);
|
|
||||||
if (mc->fixup_ram_size) {
|
|
||||||
sz = mc->fixup_ram_size(sz);
|
|
||||||
}
|
|
||||||
ram_size = sz;
|
|
||||||
if (ram_size != sz) {
|
|
||||||
error_report("ram size too large");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
maxram_size = ram_size;
|
|
||||||
|
|
||||||
if (qemu_opt_get(opts, "maxmem")) {
|
if (qemu_opt_get(opts, "maxmem")) {
|
||||||
uint64_t slots;
|
qdict_put_str(prop, "max-size", qemu_opt_get(opts, "maxmem"));
|
||||||
|
}
|
||||||
sz = qemu_opt_get_size(opts, "maxmem", 0);
|
if (qemu_opt_get(opts, "slots")) {
|
||||||
slots = qemu_opt_get_number(opts, "slots", 0);
|
qdict_put_str(prop, "slots", qemu_opt_get(opts, "slots"));
|
||||||
if (sz < ram_size) {
|
|
||||||
error_report("invalid value of -m option maxmem: "
|
|
||||||
"maximum memory size (0x%" PRIx64 ") must be at least "
|
|
||||||
"the initial memory size (0x" RAM_ADDR_FMT ")",
|
|
||||||
sz, ram_size);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
} else if (slots && sz == ram_size) {
|
|
||||||
error_report("invalid value of -m option maxmem: "
|
|
||||||
"memory slots were specified but maximum memory size "
|
|
||||||
"(0x%" PRIx64 ") is equal to the initial memory size "
|
|
||||||
"(0x" RAM_ADDR_FMT ")", sz, ram_size);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
maxram_size = sz;
|
|
||||||
ram_slots = slots;
|
|
||||||
} else if (qemu_opt_get(opts, "slots")) {
|
|
||||||
error_report("invalid -m option value: missing 'maxmem' option");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loc_pop(&loc);
|
dict = qdict_new();
|
||||||
|
qdict_put(dict, "memory", prop);
|
||||||
|
keyval_merge(machine_opts_dict, dict, &error_fatal);
|
||||||
|
qobject_unref(dict);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qemu_create_machine(QDict *qdict)
|
static void qemu_create_machine(QDict *qdict)
|
||||||
|
@ -2152,8 +2083,6 @@ static void qemu_create_machine(QDict *qdict)
|
||||||
MachineClass *machine_class = select_machine(qdict, &error_fatal);
|
MachineClass *machine_class = select_machine(qdict, &error_fatal);
|
||||||
object_set_machine_compat_props(machine_class->compat_props);
|
object_set_machine_compat_props(machine_class->compat_props);
|
||||||
|
|
||||||
set_memory_options(machine_class);
|
|
||||||
|
|
||||||
current_machine = MACHINE(object_new_with_class(OBJECT_CLASS(machine_class)));
|
current_machine = MACHINE(object_new_with_class(OBJECT_CLASS(machine_class)));
|
||||||
object_property_add_child(object_get_root(), "machine",
|
object_property_add_child(object_get_root(), "machine",
|
||||||
OBJECT(current_machine));
|
OBJECT(current_machine));
|
||||||
|
@ -2212,7 +2141,9 @@ static bool is_qemuopts_group(const char *group)
|
||||||
{
|
{
|
||||||
if (g_str_equal(group, "object") ||
|
if (g_str_equal(group, "object") ||
|
||||||
g_str_equal(group, "machine") ||
|
g_str_equal(group, "machine") ||
|
||||||
g_str_equal(group, "smp-opts")) {
|
g_str_equal(group, "smp-opts") ||
|
||||||
|
g_str_equal(group, "boot-opts") ||
|
||||||
|
g_str_equal(group, "memory")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -2234,6 +2165,10 @@ static void qemu_record_config_group(const char *group, QDict *dict,
|
||||||
keyval_merge(machine_opts_dict, dict, errp);
|
keyval_merge(machine_opts_dict, dict, errp);
|
||||||
} else if (g_str_equal(group, "smp-opts")) {
|
} else if (g_str_equal(group, "smp-opts")) {
|
||||||
machine_merge_property("smp", dict, &error_fatal);
|
machine_merge_property("smp", dict, &error_fatal);
|
||||||
|
} else if (g_str_equal(group, "boot-opts")) {
|
||||||
|
machine_merge_property("boot", dict, &error_fatal);
|
||||||
|
} else if (g_str_equal(group, "memory")) {
|
||||||
|
machine_merge_property("memory", dict, &error_fatal);
|
||||||
} else {
|
} else {
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
@ -2440,27 +2375,6 @@ static void configure_accelerators(const char *progname)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void create_default_memdev(MachineState *ms, const char *path)
|
|
||||||
{
|
|
||||||
Object *obj;
|
|
||||||
MachineClass *mc = MACHINE_GET_CLASS(ms);
|
|
||||||
|
|
||||||
obj = object_new(path ? TYPE_MEMORY_BACKEND_FILE : TYPE_MEMORY_BACKEND_RAM);
|
|
||||||
if (path) {
|
|
||||||
object_property_set_str(obj, "mem-path", path, &error_fatal);
|
|
||||||
}
|
|
||||||
object_property_set_int(obj, "size", ms->ram_size, &error_fatal);
|
|
||||||
object_property_add_child(object_get_objects_root(), mc->default_ram_id,
|
|
||||||
obj);
|
|
||||||
/* Ensure backend's memory region name is equal to mc->default_ram_id */
|
|
||||||
object_property_set_bool(obj, "x-use-canonical-path-for-ramblock-id",
|
|
||||||
false, &error_fatal);
|
|
||||||
user_creatable_complete(USER_CREATABLE(obj), &error_fatal);
|
|
||||||
object_unref(obj);
|
|
||||||
object_property_set_str(OBJECT(ms), "memory-backend", mc->default_ram_id,
|
|
||||||
&error_fatal);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void qemu_validate_options(const QDict *machine_opts)
|
static void qemu_validate_options(const QDict *machine_opts)
|
||||||
{
|
{
|
||||||
const char *kernel_filename = qdict_get_try_str(machine_opts, "kernel");
|
const char *kernel_filename = qdict_get_try_str(machine_opts, "kernel");
|
||||||
|
@ -2645,18 +2559,11 @@ static void qemu_init_displays(void)
|
||||||
|
|
||||||
static void qemu_init_board(void)
|
static void qemu_init_board(void)
|
||||||
{
|
{
|
||||||
MachineClass *machine_class = MACHINE_GET_CLASS(current_machine);
|
|
||||||
|
|
||||||
if (machine_class->default_ram_id && current_machine->ram_size &&
|
|
||||||
numa_uses_legacy_mem() && !current_machine->ram_memdev_id) {
|
|
||||||
create_default_memdev(current_machine, mem_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* process plugin before CPUs are created, but once -smp has been parsed */
|
/* process plugin before CPUs are created, but once -smp has been parsed */
|
||||||
qemu_plugin_load_list(&plugin_list, &error_fatal);
|
qemu_plugin_load_list(&plugin_list, &error_fatal);
|
||||||
|
|
||||||
/* From here on we enter MACHINE_PHASE_INITIALIZED. */
|
/* From here on we enter MACHINE_PHASE_INITIALIZED. */
|
||||||
machine_run_board_init(current_machine);
|
machine_run_board_init(current_machine, mem_path, &error_fatal);
|
||||||
|
|
||||||
drive_check_orphaned();
|
drive_check_orphaned();
|
||||||
|
|
||||||
|
@ -2979,11 +2886,7 @@ void qemu_init(int argc, char **argv, char **envp)
|
||||||
drive_add(IF_DEFAULT, 2, optarg, CDROM_OPTS);
|
drive_add(IF_DEFAULT, 2, optarg, CDROM_OPTS);
|
||||||
break;
|
break;
|
||||||
case QEMU_OPTION_boot:
|
case QEMU_OPTION_boot:
|
||||||
opts = qemu_opts_parse_noisily(qemu_find_opts("boot-opts"),
|
machine_parse_property_opt(qemu_find_opts("boot-opts"), "boot", optarg);
|
||||||
optarg, true);
|
|
||||||
if (!opts) {
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case QEMU_OPTION_fda:
|
case QEMU_OPTION_fda:
|
||||||
case QEMU_OPTION_fdb:
|
case QEMU_OPTION_fdb:
|
||||||
|
@ -3038,11 +2941,7 @@ void qemu_init(int argc, char **argv, char **envp)
|
||||||
exit(0);
|
exit(0);
|
||||||
break;
|
break;
|
||||||
case QEMU_OPTION_m:
|
case QEMU_OPTION_m:
|
||||||
opts = qemu_opts_parse_noisily(qemu_find_opts("memory"),
|
parse_memory_options(optarg);
|
||||||
optarg, true);
|
|
||||||
if (!opts) {
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
#ifdef CONFIG_TPM
|
#ifdef CONFIG_TPM
|
||||||
case QEMU_OPTION_tpmdev:
|
case QEMU_OPTION_tpmdev:
|
||||||
|
@ -3732,7 +3631,7 @@ void qemu_init(int argc, char **argv, char **envp)
|
||||||
|
|
||||||
machine_class = MACHINE_GET_CLASS(current_machine);
|
machine_class = MACHINE_GET_CLASS(current_machine);
|
||||||
if (!qtest_enabled() && machine_class->deprecation_reason) {
|
if (!qtest_enabled() && machine_class->deprecation_reason) {
|
||||||
error_report("Machine type '%s' is deprecated: %s",
|
warn_report("Machine type '%s' is deprecated: %s",
|
||||||
machine_class->name, machine_class->deprecation_reason);
|
machine_class->name, machine_class->deprecation_reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5022,6 +5022,37 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w,
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void x86_cpu_get_cache_cpuid(uint32_t func, uint32_t index,
|
||||||
|
uint32_t *eax, uint32_t *ebx,
|
||||||
|
uint32_t *ecx, uint32_t *edx)
|
||||||
|
{
|
||||||
|
uint32_t level, unused;
|
||||||
|
|
||||||
|
/* Only return valid host leaves. */
|
||||||
|
switch (func) {
|
||||||
|
case 2:
|
||||||
|
case 4:
|
||||||
|
host_cpuid(0, 0, &level, &unused, &unused, &unused);
|
||||||
|
break;
|
||||||
|
case 0x80000005:
|
||||||
|
case 0x80000006:
|
||||||
|
case 0x8000001d:
|
||||||
|
host_cpuid(0x80000000, 0, &level, &unused, &unused, &unused);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (func > level) {
|
||||||
|
*eax = 0;
|
||||||
|
*ebx = 0;
|
||||||
|
*ecx = 0;
|
||||||
|
*edx = 0;
|
||||||
|
} else {
|
||||||
|
host_cpuid(func, index, eax, ebx, ecx, edx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Only for builtin_x86_defs models initialized with x86_register_cpudef_types.
|
* Only for builtin_x86_defs models initialized with x86_register_cpudef_types.
|
||||||
*/
|
*/
|
||||||
|
@ -5280,7 +5311,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
|
||||||
case 2:
|
case 2:
|
||||||
/* cache info: needed for Pentium Pro compatibility */
|
/* cache info: needed for Pentium Pro compatibility */
|
||||||
if (cpu->cache_info_passthrough) {
|
if (cpu->cache_info_passthrough) {
|
||||||
host_cpuid(index, 0, eax, ebx, ecx, edx);
|
x86_cpu_get_cache_cpuid(index, 0, eax, ebx, ecx, edx);
|
||||||
break;
|
break;
|
||||||
} else if (cpu->vendor_cpuid_only && IS_AMD_CPU(env)) {
|
} else if (cpu->vendor_cpuid_only && IS_AMD_CPU(env)) {
|
||||||
*eax = *ebx = *ecx = *edx = 0;
|
*eax = *ebx = *ecx = *edx = 0;
|
||||||
|
@ -5300,7 +5331,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
|
||||||
case 4:
|
case 4:
|
||||||
/* cache info: needed for Core compatibility */
|
/* cache info: needed for Core compatibility */
|
||||||
if (cpu->cache_info_passthrough) {
|
if (cpu->cache_info_passthrough) {
|
||||||
host_cpuid(index, count, eax, ebx, ecx, edx);
|
x86_cpu_get_cache_cpuid(index, count, eax, ebx, ecx, edx);
|
||||||
/* QEMU gives out its own APIC IDs, never pass down bits 31..26. */
|
/* QEMU gives out its own APIC IDs, never pass down bits 31..26. */
|
||||||
*eax &= ~0xFC000000;
|
*eax &= ~0xFC000000;
|
||||||
if ((*eax & 31) && cs->nr_cores > 1) {
|
if ((*eax & 31) && cs->nr_cores > 1) {
|
||||||
|
@ -5702,7 +5733,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
|
||||||
case 0x80000005:
|
case 0x80000005:
|
||||||
/* cache info (L1 cache) */
|
/* cache info (L1 cache) */
|
||||||
if (cpu->cache_info_passthrough) {
|
if (cpu->cache_info_passthrough) {
|
||||||
host_cpuid(index, 0, eax, ebx, ecx, edx);
|
x86_cpu_get_cache_cpuid(index, 0, eax, ebx, ecx, edx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
*eax = (L1_DTLB_2M_ASSOC << 24) | (L1_DTLB_2M_ENTRIES << 16) |
|
*eax = (L1_DTLB_2M_ASSOC << 24) | (L1_DTLB_2M_ENTRIES << 16) |
|
||||||
|
@ -5715,7 +5746,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
|
||||||
case 0x80000006:
|
case 0x80000006:
|
||||||
/* cache info (L2 cache) */
|
/* cache info (L2 cache) */
|
||||||
if (cpu->cache_info_passthrough) {
|
if (cpu->cache_info_passthrough) {
|
||||||
host_cpuid(index, 0, eax, ebx, ecx, edx);
|
x86_cpu_get_cache_cpuid(index, 0, eax, ebx, ecx, edx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
*eax = (AMD_ENC_ASSOC(L2_DTLB_2M_ASSOC) << 28) |
|
*eax = (AMD_ENC_ASSOC(L2_DTLB_2M_ASSOC) << 28) |
|
||||||
|
@ -5775,7 +5806,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
|
||||||
case 0x8000001D:
|
case 0x8000001D:
|
||||||
*eax = 0;
|
*eax = 0;
|
||||||
if (cpu->cache_info_passthrough) {
|
if (cpu->cache_info_passthrough) {
|
||||||
host_cpuid(index, count, eax, ebx, ecx, edx);
|
x86_cpu_get_cache_cpuid(index, count, eax, ebx, ecx, edx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
switch (count) {
|
switch (count) {
|
||||||
|
|
|
@ -233,6 +233,12 @@ static void test_e1000e_multiple_transfers(void *obj, void *data,
|
||||||
static void test_e1000e_hotplug(void *obj, void *data, QGuestAllocator * alloc)
|
static void test_e1000e_hotplug(void *obj, void *data, QGuestAllocator * alloc)
|
||||||
{
|
{
|
||||||
QTestState *qts = global_qtest; /* TODO: get rid of global_qtest here */
|
QTestState *qts = global_qtest; /* TODO: get rid of global_qtest here */
|
||||||
|
QE1000E_PCI *dev = obj;
|
||||||
|
|
||||||
|
if (dev->pci_dev.bus->not_hotpluggable) {
|
||||||
|
g_test_skip("pci bus does not support hotplug");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
qtest_qmp_device_add(qts, "e1000e", "e1000e_net", "{'addr': '0x06'}");
|
qtest_qmp_device_add(qts, "e1000e", "e1000e_net", "{'addr': '0x06'}");
|
||||||
qpci_unplug_acpi_device_test(qts, "e1000e_net", 0x06);
|
qpci_unplug_acpi_device_test(qts, "e1000e_net", 0x06);
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
#include "malloc.h"
|
#include "malloc.h"
|
||||||
#include "qgraph.h"
|
#include "qgraph.h"
|
||||||
#include "virtio-mmio.h"
|
#include "virtio-mmio.h"
|
||||||
|
#include "generic-pcihost.h"
|
||||||
|
#include "hw/pci/pci_regs.h"
|
||||||
|
|
||||||
#define ARM_PAGE_SIZE 4096
|
#define ARM_PAGE_SIZE 4096
|
||||||
#define VIRTIO_MMIO_BASE_ADDR 0x0A003E00
|
#define VIRTIO_MMIO_BASE_ADDR 0x0A003E00
|
||||||
|
@ -35,6 +37,7 @@ struct QVirtMachine {
|
||||||
QOSGraphObject obj;
|
QOSGraphObject obj;
|
||||||
QGuestAllocator alloc;
|
QGuestAllocator alloc;
|
||||||
QVirtioMMIODevice virtio_mmio;
|
QVirtioMMIODevice virtio_mmio;
|
||||||
|
QGenericPCIHost bridge;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void virt_destructor(QOSGraphObject *obj)
|
static void virt_destructor(QOSGraphObject *obj)
|
||||||
|
@ -57,11 +60,13 @@ static void *virt_get_driver(void *object, const char *interface)
|
||||||
static QOSGraphObject *virt_get_device(void *obj, const char *device)
|
static QOSGraphObject *virt_get_device(void *obj, const char *device)
|
||||||
{
|
{
|
||||||
QVirtMachine *machine = obj;
|
QVirtMachine *machine = obj;
|
||||||
if (!g_strcmp0(device, "virtio-mmio")) {
|
if (!g_strcmp0(device, "generic-pcihost")) {
|
||||||
|
return &machine->bridge.obj;
|
||||||
|
} else if (!g_strcmp0(device, "virtio-mmio")) {
|
||||||
return &machine->virtio_mmio.obj;
|
return &machine->virtio_mmio.obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr, "%s not present in arm/virtio\n", device);
|
fprintf(stderr, "%s not present in arm/virt\n", device);
|
||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,16 +81,22 @@ static void *qos_create_machine_arm_virt(QTestState *qts)
|
||||||
qvirtio_mmio_init_device(&machine->virtio_mmio, qts, VIRTIO_MMIO_BASE_ADDR,
|
qvirtio_mmio_init_device(&machine->virtio_mmio, qts, VIRTIO_MMIO_BASE_ADDR,
|
||||||
VIRTIO_MMIO_SIZE);
|
VIRTIO_MMIO_SIZE);
|
||||||
|
|
||||||
|
qos_create_generic_pcihost(&machine->bridge, qts, &machine->alloc);
|
||||||
|
|
||||||
machine->obj.get_device = virt_get_device;
|
machine->obj.get_device = virt_get_device;
|
||||||
machine->obj.get_driver = virt_get_driver;
|
machine->obj.get_driver = virt_get_driver;
|
||||||
machine->obj.destructor = virt_destructor;
|
machine->obj.destructor = virt_destructor;
|
||||||
return machine;
|
return machine;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void virtio_mmio_register_nodes(void)
|
static void virt_machine_register_nodes(void)
|
||||||
{
|
{
|
||||||
qos_node_create_machine("arm/virt", qos_create_machine_arm_virt);
|
qos_node_create_machine("arm/virt", qos_create_machine_arm_virt);
|
||||||
qos_node_contains("arm/virt", "virtio-mmio", NULL);
|
qos_node_contains("arm/virt", "virtio-mmio", NULL);
|
||||||
|
|
||||||
|
qos_node_create_machine_args("aarch64/virt", qos_create_machine_arm_virt,
|
||||||
|
" -cpu max");
|
||||||
|
qos_node_contains("aarch64/virt", "generic-pcihost", NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
libqos_init(virtio_mmio_register_nodes);
|
libqos_init(virt_machine_register_nodes);
|
||||||
|
|
|
@ -0,0 +1,231 @@
|
||||||
|
/*
|
||||||
|
* libqos PCI bindings for generic PCI
|
||||||
|
*
|
||||||
|
* Copyright Red Hat Inc., 2022
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Eric Auger <eric.auger@redhat.com>
|
||||||
|
*
|
||||||
|
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||||
|
* See the COPYING file in the top-level directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "../libqtest.h"
|
||||||
|
#include "generic-pcihost.h"
|
||||||
|
#include "qapi/qmp/qdict.h"
|
||||||
|
#include "hw/pci/pci_regs.h"
|
||||||
|
#include "qemu/host-utils.h"
|
||||||
|
|
||||||
|
#include "qemu/module.h"
|
||||||
|
|
||||||
|
/* QGenericPCIHost */
|
||||||
|
|
||||||
|
QOSGraphObject *generic_pcihost_get_device(void *obj, const char *device)
|
||||||
|
{
|
||||||
|
QGenericPCIHost *host = obj;
|
||||||
|
if (!g_strcmp0(device, "pci-bus-generic")) {
|
||||||
|
return &host->pci.obj;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "%s not present in generic-pcihost\n", device);
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
|
||||||
|
void qos_create_generic_pcihost(QGenericPCIHost *host,
|
||||||
|
QTestState *qts,
|
||||||
|
QGuestAllocator *alloc)
|
||||||
|
{
|
||||||
|
host->obj.get_device = generic_pcihost_get_device;
|
||||||
|
qpci_init_generic(&host->pci, qts, alloc, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t qpci_generic_pio_readb(QPCIBus *bus, uint32_t addr)
|
||||||
|
{
|
||||||
|
QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus);
|
||||||
|
|
||||||
|
return qtest_readb(bus->qts, s->gpex_pio_base + addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qpci_generic_pio_writeb(QPCIBus *bus, uint32_t addr, uint8_t val)
|
||||||
|
{
|
||||||
|
QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus);
|
||||||
|
|
||||||
|
qtest_writeb(bus->qts, s->gpex_pio_base + addr, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t qpci_generic_pio_readw(QPCIBus *bus, uint32_t addr)
|
||||||
|
{
|
||||||
|
QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus);
|
||||||
|
|
||||||
|
return qtest_readw(bus->qts, s->gpex_pio_base + addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qpci_generic_pio_writew(QPCIBus *bus, uint32_t addr, uint16_t val)
|
||||||
|
{
|
||||||
|
QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus);
|
||||||
|
|
||||||
|
qtest_writew(bus->qts, s->gpex_pio_base + addr, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t qpci_generic_pio_readl(QPCIBus *bus, uint32_t addr)
|
||||||
|
{
|
||||||
|
QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus);
|
||||||
|
|
||||||
|
return qtest_readl(bus->qts, s->gpex_pio_base + addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qpci_generic_pio_writel(QPCIBus *bus, uint32_t addr, uint32_t val)
|
||||||
|
{
|
||||||
|
QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus);
|
||||||
|
|
||||||
|
qtest_writel(bus->qts, s->gpex_pio_base + addr, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t qpci_generic_pio_readq(QPCIBus *bus, uint32_t addr)
|
||||||
|
{
|
||||||
|
QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus);
|
||||||
|
|
||||||
|
return qtest_readq(bus->qts, s->gpex_pio_base + addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qpci_generic_pio_writeq(QPCIBus *bus, uint32_t addr, uint64_t val)
|
||||||
|
{
|
||||||
|
QGenericPCIBus *s = container_of(bus, QGenericPCIBus, bus);
|
||||||
|
|
||||||
|
qtest_writeq(bus->qts, s->gpex_pio_base + addr, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qpci_generic_memread(QPCIBus *bus, uint32_t addr, void *buf, size_t len)
|
||||||
|
{
|
||||||
|
qtest_memread(bus->qts, addr, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qpci_generic_memwrite(QPCIBus *bus, uint32_t addr,
|
||||||
|
const void *buf, size_t len)
|
||||||
|
{
|
||||||
|
qtest_memwrite(bus->qts, addr, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t qpci_generic_config_readb(QPCIBus *bus, int devfn, uint8_t offset)
|
||||||
|
{
|
||||||
|
QGenericPCIBus *gbus = container_of(bus, QGenericPCIBus, bus);
|
||||||
|
uint64_t addr = gbus->ecam_alloc_ptr + ((0 << 20) | (devfn << 12) | offset);
|
||||||
|
uint8_t val;
|
||||||
|
|
||||||
|
qtest_memread(bus->qts, addr, &val, 1);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t qpci_generic_config_readw(QPCIBus *bus, int devfn, uint8_t offset)
|
||||||
|
{
|
||||||
|
QGenericPCIBus *gbus = container_of(bus, QGenericPCIBus, bus);
|
||||||
|
uint64_t addr = gbus->ecam_alloc_ptr + ((0 << 20) | (devfn << 12) | offset);
|
||||||
|
uint16_t val;
|
||||||
|
|
||||||
|
qtest_memread(bus->qts, addr, &val, 2);
|
||||||
|
return le16_to_cpu(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t qpci_generic_config_readl(QPCIBus *bus, int devfn, uint8_t offset)
|
||||||
|
{
|
||||||
|
QGenericPCIBus *gbus = container_of(bus, QGenericPCIBus, bus);
|
||||||
|
uint64_t addr = gbus->ecam_alloc_ptr + ((0 << 20) | (devfn << 12) | offset);
|
||||||
|
uint32_t val;
|
||||||
|
|
||||||
|
qtest_memread(bus->qts, addr, &val, 4);
|
||||||
|
return le32_to_cpu(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
qpci_generic_config_writeb(QPCIBus *bus, int devfn, uint8_t offset, uint8_t value)
|
||||||
|
{
|
||||||
|
QGenericPCIBus *gbus = container_of(bus, QGenericPCIBus, bus);
|
||||||
|
uint64_t addr = gbus->ecam_alloc_ptr + ((0 << 20) | (devfn << 12) | offset);
|
||||||
|
|
||||||
|
qtest_memwrite(bus->qts, addr, &value, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
qpci_generic_config_writew(QPCIBus *bus, int devfn, uint8_t offset, uint16_t value)
|
||||||
|
{
|
||||||
|
QGenericPCIBus *gbus = container_of(bus, QGenericPCIBus, bus);
|
||||||
|
uint64_t addr = gbus->ecam_alloc_ptr + ((0 << 20) | (devfn << 12) | offset);
|
||||||
|
uint16_t val = cpu_to_le16(value);
|
||||||
|
|
||||||
|
qtest_memwrite(bus->qts, addr, &val, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
qpci_generic_config_writel(QPCIBus *bus, int devfn, uint8_t offset, uint32_t value)
|
||||||
|
{
|
||||||
|
QGenericPCIBus *gbus = container_of(bus, QGenericPCIBus, bus);
|
||||||
|
uint64_t addr = gbus->ecam_alloc_ptr + ((0 << 20) | (devfn << 12) | offset);
|
||||||
|
uint32_t val = cpu_to_le32(value);
|
||||||
|
|
||||||
|
qtest_memwrite(bus->qts, addr, &val, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *qpci_generic_get_driver(void *obj, const char *interface)
|
||||||
|
{
|
||||||
|
QGenericPCIBus *qpci = obj;
|
||||||
|
if (!g_strcmp0(interface, "pci-bus")) {
|
||||||
|
return &qpci->bus;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "%s not present in pci-bus-generic\n", interface);
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
|
||||||
|
void qpci_init_generic(QGenericPCIBus *qpci, QTestState *qts,
|
||||||
|
QGuestAllocator *alloc, bool hotpluggable)
|
||||||
|
{
|
||||||
|
assert(qts);
|
||||||
|
|
||||||
|
qpci->gpex_pio_base = 0x3eff0000;
|
||||||
|
qpci->bus.not_hotpluggable = !hotpluggable;
|
||||||
|
qpci->bus.has_buggy_msi = false;
|
||||||
|
|
||||||
|
qpci->bus.pio_readb = qpci_generic_pio_readb;
|
||||||
|
qpci->bus.pio_readw = qpci_generic_pio_readw;
|
||||||
|
qpci->bus.pio_readl = qpci_generic_pio_readl;
|
||||||
|
qpci->bus.pio_readq = qpci_generic_pio_readq;
|
||||||
|
|
||||||
|
qpci->bus.pio_writeb = qpci_generic_pio_writeb;
|
||||||
|
qpci->bus.pio_writew = qpci_generic_pio_writew;
|
||||||
|
qpci->bus.pio_writel = qpci_generic_pio_writel;
|
||||||
|
qpci->bus.pio_writeq = qpci_generic_pio_writeq;
|
||||||
|
|
||||||
|
qpci->bus.memread = qpci_generic_memread;
|
||||||
|
qpci->bus.memwrite = qpci_generic_memwrite;
|
||||||
|
|
||||||
|
qpci->bus.config_readb = qpci_generic_config_readb;
|
||||||
|
qpci->bus.config_readw = qpci_generic_config_readw;
|
||||||
|
qpci->bus.config_readl = qpci_generic_config_readl;
|
||||||
|
|
||||||
|
qpci->bus.config_writeb = qpci_generic_config_writeb;
|
||||||
|
qpci->bus.config_writew = qpci_generic_config_writew;
|
||||||
|
qpci->bus.config_writel = qpci_generic_config_writel;
|
||||||
|
|
||||||
|
qpci->bus.qts = qts;
|
||||||
|
qpci->bus.pio_alloc_ptr = 0x0000;
|
||||||
|
qpci->bus.pio_limit = 0x10000;
|
||||||
|
qpci->bus.mmio_alloc_ptr = 0x10000000;
|
||||||
|
qpci->bus.mmio_limit = 0x2eff0000;
|
||||||
|
qpci->ecam_alloc_ptr = 0x4010000000;
|
||||||
|
|
||||||
|
qpci->obj.get_driver = qpci_generic_get_driver;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qpci_generic_register_nodes(void)
|
||||||
|
{
|
||||||
|
qos_node_create_driver("pci-bus-generic", NULL);
|
||||||
|
qos_node_produces("pci-bus-generic", "pci-bus");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qpci_generic_pci_register_nodes(void)
|
||||||
|
{
|
||||||
|
qos_node_create_driver("generic-pcihost", NULL);
|
||||||
|
qos_node_contains("generic-pcihost", "pci-bus-generic", NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
libqos_init(qpci_generic_register_nodes);
|
||||||
|
libqos_init(qpci_generic_pci_register_nodes);
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* libqos Generic PCI bindings and generic pci host bridge
|
||||||
|
*
|
||||||
|
* Copyright Red Hat Inc., 2022
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Eric Auger <eric.auger@redhat.com>
|
||||||
|
*
|
||||||
|
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||||
|
* See the COPYING file in the top-level directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIBQOS_GENERIC_PCIHOST_H
|
||||||
|
#define LIBQOS_GENERIC_PCIHOST_H
|
||||||
|
|
||||||
|
#include "pci.h"
|
||||||
|
#include "malloc.h"
|
||||||
|
#include "qgraph.h"
|
||||||
|
|
||||||
|
typedef struct QGenericPCIBus {
|
||||||
|
QOSGraphObject obj;
|
||||||
|
QPCIBus bus;
|
||||||
|
uint64_t gpex_pio_base;
|
||||||
|
uint64_t ecam_alloc_ptr;
|
||||||
|
} QGenericPCIBus;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* qpci_init_generic():
|
||||||
|
* @ret: A valid QGenericPCIBus * pointer
|
||||||
|
* @qts: The %QTestState
|
||||||
|
* @alloc: A previously initialized @alloc providing memory for @qts
|
||||||
|
* @bool: devices can be hotplugged on this bus
|
||||||
|
*
|
||||||
|
* This function initializes an already allocated
|
||||||
|
* QGenericPCIBus object.
|
||||||
|
*/
|
||||||
|
void qpci_init_generic(QGenericPCIBus *ret, QTestState *qts,
|
||||||
|
QGuestAllocator *alloc, bool hotpluggable);
|
||||||
|
|
||||||
|
/* QGenericPCIHost */
|
||||||
|
|
||||||
|
typedef struct QGenericPCIHost QGenericPCIHost;
|
||||||
|
|
||||||
|
struct QGenericPCIHost {
|
||||||
|
QOSGraphObject obj;
|
||||||
|
QGenericPCIBus pci;
|
||||||
|
};
|
||||||
|
|
||||||
|
QOSGraphObject *generic_pcihost_get_device(void *obj, const char *device);
|
||||||
|
void qos_create_generic_pcihost(QGenericPCIHost *host,
|
||||||
|
QTestState *qts,
|
||||||
|
QGuestAllocator *alloc);
|
||||||
|
|
||||||
|
#endif
|
|
@ -45,6 +45,7 @@ libqos_srcs = files(
|
||||||
'virtio-scsi.c',
|
'virtio-scsi.c',
|
||||||
'virtio-serial.c',
|
'virtio-serial.c',
|
||||||
'virtio-iommu.c',
|
'virtio-iommu.c',
|
||||||
|
'generic-pcihost.c',
|
||||||
|
|
||||||
# qgraph machines:
|
# qgraph machines:
|
||||||
'aarch64-xlnx-zcu102-machine.c',
|
'aarch64-xlnx-zcu102-machine.c',
|
||||||
|
|
|
@ -150,6 +150,7 @@ void qpci_init_pc(QPCIBusPC *qpci, QTestState *qts, QGuestAllocator *alloc)
|
||||||
|
|
||||||
qpci->bus.qts = qts;
|
qpci->bus.qts = qts;
|
||||||
qpci->bus.pio_alloc_ptr = 0xc000;
|
qpci->bus.pio_alloc_ptr = 0xc000;
|
||||||
|
qpci->bus.pio_limit = 0x10000;
|
||||||
qpci->bus.mmio_alloc_ptr = 0xE0000000;
|
qpci->bus.mmio_alloc_ptr = 0xE0000000;
|
||||||
qpci->bus.mmio_limit = 0x100000000ULL;
|
qpci->bus.mmio_limit = 0x100000000ULL;
|
||||||
|
|
||||||
|
|
|
@ -197,6 +197,7 @@ void qpci_init_spapr(QPCIBusSPAPR *qpci, QTestState *qts,
|
||||||
|
|
||||||
qpci->bus.qts = qts;
|
qpci->bus.qts = qts;
|
||||||
qpci->bus.pio_alloc_ptr = 0xc000;
|
qpci->bus.pio_alloc_ptr = 0xc000;
|
||||||
|
qpci->bus.pio_limit = 0x10000;
|
||||||
qpci->bus.mmio_alloc_ptr = qpci->mmio32.pci_base;
|
qpci->bus.mmio_alloc_ptr = qpci->mmio32.pci_base;
|
||||||
qpci->bus.mmio_limit = qpci->mmio32.pci_base + qpci->mmio32.size;
|
qpci->bus.mmio_limit = qpci->mmio32.pci_base + qpci->mmio32.size;
|
||||||
|
|
||||||
|
|
|
@ -398,44 +398,56 @@ void qpci_config_writel(QPCIDevice *dev, uint8_t offset, uint32_t value)
|
||||||
|
|
||||||
uint8_t qpci_io_readb(QPCIDevice *dev, QPCIBar token, uint64_t off)
|
uint8_t qpci_io_readb(QPCIDevice *dev, QPCIBar token, uint64_t off)
|
||||||
{
|
{
|
||||||
if (token.addr < QPCI_PIO_LIMIT) {
|
QPCIBus *bus = dev->bus;
|
||||||
return dev->bus->pio_readb(dev->bus, token.addr + off);
|
|
||||||
|
if (token.is_io) {
|
||||||
|
return bus->pio_readb(bus, token.addr + off);
|
||||||
} else {
|
} else {
|
||||||
uint8_t val;
|
uint8_t val;
|
||||||
dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val));
|
|
||||||
|
bus->memread(dev->bus, token.addr + off, &val, sizeof(val));
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t qpci_io_readw(QPCIDevice *dev, QPCIBar token, uint64_t off)
|
uint16_t qpci_io_readw(QPCIDevice *dev, QPCIBar token, uint64_t off)
|
||||||
{
|
{
|
||||||
if (token.addr < QPCI_PIO_LIMIT) {
|
QPCIBus *bus = dev->bus;
|
||||||
return dev->bus->pio_readw(dev->bus, token.addr + off);
|
|
||||||
|
if (token.is_io) {
|
||||||
|
return bus->pio_readw(bus, token.addr + off);
|
||||||
} else {
|
} else {
|
||||||
uint16_t val;
|
uint16_t val;
|
||||||
dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val));
|
|
||||||
|
bus->memread(bus, token.addr + off, &val, sizeof(val));
|
||||||
return le16_to_cpu(val);
|
return le16_to_cpu(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t qpci_io_readl(QPCIDevice *dev, QPCIBar token, uint64_t off)
|
uint32_t qpci_io_readl(QPCIDevice *dev, QPCIBar token, uint64_t off)
|
||||||
{
|
{
|
||||||
if (token.addr < QPCI_PIO_LIMIT) {
|
QPCIBus *bus = dev->bus;
|
||||||
return dev->bus->pio_readl(dev->bus, token.addr + off);
|
|
||||||
|
if (token.is_io) {
|
||||||
|
return bus->pio_readl(bus, token.addr + off);
|
||||||
} else {
|
} else {
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val));
|
|
||||||
|
bus->memread(dev->bus, token.addr + off, &val, sizeof(val));
|
||||||
return le32_to_cpu(val);
|
return le32_to_cpu(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t qpci_io_readq(QPCIDevice *dev, QPCIBar token, uint64_t off)
|
uint64_t qpci_io_readq(QPCIDevice *dev, QPCIBar token, uint64_t off)
|
||||||
{
|
{
|
||||||
if (token.addr < QPCI_PIO_LIMIT) {
|
QPCIBus *bus = dev->bus;
|
||||||
return dev->bus->pio_readq(dev->bus, token.addr + off);
|
|
||||||
|
if (token.is_io) {
|
||||||
|
return bus->pio_readq(bus, token.addr + off);
|
||||||
} else {
|
} else {
|
||||||
uint64_t val;
|
uint64_t val;
|
||||||
dev->bus->memread(dev->bus, token.addr + off, &val, sizeof(val));
|
|
||||||
|
bus->memread(bus, token.addr + off, &val, sizeof(val));
|
||||||
return le64_to_cpu(val);
|
return le64_to_cpu(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -443,57 +455,65 @@ uint64_t qpci_io_readq(QPCIDevice *dev, QPCIBar token, uint64_t off)
|
||||||
void qpci_io_writeb(QPCIDevice *dev, QPCIBar token, uint64_t off,
|
void qpci_io_writeb(QPCIDevice *dev, QPCIBar token, uint64_t off,
|
||||||
uint8_t value)
|
uint8_t value)
|
||||||
{
|
{
|
||||||
if (token.addr < QPCI_PIO_LIMIT) {
|
QPCIBus *bus = dev->bus;
|
||||||
dev->bus->pio_writeb(dev->bus, token.addr + off, value);
|
|
||||||
|
if (token.is_io) {
|
||||||
|
bus->pio_writeb(bus, token.addr + off, value);
|
||||||
} else {
|
} else {
|
||||||
dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value));
|
bus->memwrite(bus, token.addr + off, &value, sizeof(value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void qpci_io_writew(QPCIDevice *dev, QPCIBar token, uint64_t off,
|
void qpci_io_writew(QPCIDevice *dev, QPCIBar token, uint64_t off,
|
||||||
uint16_t value)
|
uint16_t value)
|
||||||
{
|
{
|
||||||
if (token.addr < QPCI_PIO_LIMIT) {
|
QPCIBus *bus = dev->bus;
|
||||||
dev->bus->pio_writew(dev->bus, token.addr + off, value);
|
|
||||||
|
if (token.is_io) {
|
||||||
|
bus->pio_writew(bus, token.addr + off, value);
|
||||||
} else {
|
} else {
|
||||||
value = cpu_to_le16(value);
|
value = cpu_to_le16(value);
|
||||||
dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value));
|
bus->memwrite(bus, token.addr + off, &value, sizeof(value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void qpci_io_writel(QPCIDevice *dev, QPCIBar token, uint64_t off,
|
void qpci_io_writel(QPCIDevice *dev, QPCIBar token, uint64_t off,
|
||||||
uint32_t value)
|
uint32_t value)
|
||||||
{
|
{
|
||||||
if (token.addr < QPCI_PIO_LIMIT) {
|
QPCIBus *bus = dev->bus;
|
||||||
dev->bus->pio_writel(dev->bus, token.addr + off, value);
|
|
||||||
|
if (token.is_io) {
|
||||||
|
bus->pio_writel(bus, token.addr + off, value);
|
||||||
} else {
|
} else {
|
||||||
value = cpu_to_le32(value);
|
value = cpu_to_le32(value);
|
||||||
dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value));
|
bus->memwrite(bus, token.addr + off, &value, sizeof(value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void qpci_io_writeq(QPCIDevice *dev, QPCIBar token, uint64_t off,
|
void qpci_io_writeq(QPCIDevice *dev, QPCIBar token, uint64_t off,
|
||||||
uint64_t value)
|
uint64_t value)
|
||||||
{
|
{
|
||||||
if (token.addr < QPCI_PIO_LIMIT) {
|
QPCIBus *bus = dev->bus;
|
||||||
dev->bus->pio_writeq(dev->bus, token.addr + off, value);
|
|
||||||
|
if (token.is_io) {
|
||||||
|
bus->pio_writeq(bus, token.addr + off, value);
|
||||||
} else {
|
} else {
|
||||||
value = cpu_to_le64(value);
|
value = cpu_to_le64(value);
|
||||||
dev->bus->memwrite(dev->bus, token.addr + off, &value, sizeof(value));
|
bus->memwrite(bus, token.addr + off, &value, sizeof(value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void qpci_memread(QPCIDevice *dev, QPCIBar token, uint64_t off,
|
void qpci_memread(QPCIDevice *dev, QPCIBar token, uint64_t off,
|
||||||
void *buf, size_t len)
|
void *buf, size_t len)
|
||||||
{
|
{
|
||||||
g_assert(token.addr >= QPCI_PIO_LIMIT);
|
g_assert(!token.is_io);
|
||||||
dev->bus->memread(dev->bus, token.addr + off, buf, len);
|
dev->bus->memread(dev->bus, token.addr + off, buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void qpci_memwrite(QPCIDevice *dev, QPCIBar token, uint64_t off,
|
void qpci_memwrite(QPCIDevice *dev, QPCIBar token, uint64_t off,
|
||||||
const void *buf, size_t len)
|
const void *buf, size_t len)
|
||||||
{
|
{
|
||||||
g_assert(token.addr >= QPCI_PIO_LIMIT);
|
g_assert(!token.is_io);
|
||||||
dev->bus->memwrite(dev->bus, token.addr + off, buf, len);
|
dev->bus->memwrite(dev->bus, token.addr + off, buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -534,9 +554,10 @@ QPCIBar qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr)
|
||||||
loc = QEMU_ALIGN_UP(bus->pio_alloc_ptr, size);
|
loc = QEMU_ALIGN_UP(bus->pio_alloc_ptr, size);
|
||||||
|
|
||||||
g_assert(loc >= bus->pio_alloc_ptr);
|
g_assert(loc >= bus->pio_alloc_ptr);
|
||||||
g_assert(loc + size <= QPCI_PIO_LIMIT); /* Keep PIO below 64kiB */
|
g_assert(loc + size <= bus->pio_limit);
|
||||||
|
|
||||||
bus->pio_alloc_ptr = loc + size;
|
bus->pio_alloc_ptr = loc + size;
|
||||||
|
bar.is_io = true;
|
||||||
|
|
||||||
qpci_config_writel(dev, bar_reg, loc | PCI_BASE_ADDRESS_SPACE_IO);
|
qpci_config_writel(dev, bar_reg, loc | PCI_BASE_ADDRESS_SPACE_IO);
|
||||||
} else {
|
} else {
|
||||||
|
@ -547,6 +568,7 @@ QPCIBar qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr)
|
||||||
g_assert(loc + size <= bus->mmio_limit);
|
g_assert(loc + size <= bus->mmio_limit);
|
||||||
|
|
||||||
bus->mmio_alloc_ptr = loc + size;
|
bus->mmio_alloc_ptr = loc + size;
|
||||||
|
bar.is_io = false;
|
||||||
|
|
||||||
qpci_config_writel(dev, bar_reg, loc);
|
qpci_config_writel(dev, bar_reg, loc);
|
||||||
}
|
}
|
||||||
|
@ -562,7 +584,7 @@ void qpci_iounmap(QPCIDevice *dev, QPCIBar bar)
|
||||||
|
|
||||||
QPCIBar qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr)
|
QPCIBar qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr)
|
||||||
{
|
{
|
||||||
QPCIBar bar = { .addr = addr };
|
QPCIBar bar = { .addr = addr, .is_io = true };
|
||||||
return bar;
|
return bar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,6 @@
|
||||||
#include "../libqtest.h"
|
#include "../libqtest.h"
|
||||||
#include "qgraph.h"
|
#include "qgraph.h"
|
||||||
|
|
||||||
#define QPCI_PIO_LIMIT 0x10000
|
|
||||||
|
|
||||||
#define QPCI_DEVFN(dev, fn) (((dev) << 3) | (fn))
|
#define QPCI_DEVFN(dev, fn) (((dev) << 3) | (fn))
|
||||||
|
|
||||||
typedef struct QPCIDevice QPCIDevice;
|
typedef struct QPCIDevice QPCIDevice;
|
||||||
|
@ -51,14 +49,16 @@ struct QPCIBus {
|
||||||
uint8_t offset, uint32_t value);
|
uint8_t offset, uint32_t value);
|
||||||
|
|
||||||
QTestState *qts;
|
QTestState *qts;
|
||||||
uint16_t pio_alloc_ptr;
|
uint64_t pio_alloc_ptr, pio_limit;
|
||||||
uint64_t mmio_alloc_ptr, mmio_limit;
|
uint64_t mmio_alloc_ptr, mmio_limit;
|
||||||
bool has_buggy_msi; /* TRUE for spapr, FALSE for pci */
|
bool has_buggy_msi; /* TRUE for spapr, FALSE for pci */
|
||||||
|
bool not_hotpluggable; /* TRUE if devices cannot be hotplugged */
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct QPCIBar {
|
struct QPCIBar {
|
||||||
uint64_t addr;
|
uint64_t addr;
|
||||||
|
bool is_io;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct QPCIDevice
|
struct QPCIDevice
|
||||||
|
|
|
@ -676,6 +676,11 @@ static void pci_hotplug(void *obj, void *data, QGuestAllocator *t_alloc)
|
||||||
QVirtioPCIDevice *dev;
|
QVirtioPCIDevice *dev;
|
||||||
QTestState *qts = dev1->pdev->bus->qts;
|
QTestState *qts = dev1->pdev->bus->qts;
|
||||||
|
|
||||||
|
if (dev1->pdev->bus->not_hotpluggable) {
|
||||||
|
g_test_skip("pci bus does not support hotplug");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* plug secondary disk */
|
/* plug secondary disk */
|
||||||
qtest_qmp_device_add(qts, "vhost-user-blk-pci", "drv1",
|
qtest_qmp_device_add(qts, "vhost-user-blk-pci", "drv1",
|
||||||
"{'addr': %s, 'chardev': 'char2'}",
|
"{'addr': %s, 'chardev': 'char2'}",
|
||||||
|
@ -703,6 +708,11 @@ static void multiqueue(void *obj, void *data, QGuestAllocator *t_alloc)
|
||||||
uint64_t features;
|
uint64_t features;
|
||||||
uint16_t num_queues;
|
uint16_t num_queues;
|
||||||
|
|
||||||
|
if (pdev1->pdev->bus->not_hotpluggable) {
|
||||||
|
g_test_skip("bus pci.0 does not support hotplug");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The primary device has 1 queue and VIRTIO_BLK_F_MQ is not enabled. The
|
* The primary device has 1 queue and VIRTIO_BLK_F_MQ is not enabled. The
|
||||||
* VIRTIO specification allows VIRTIO_BLK_F_MQ to be enabled when there is
|
* VIRTIO specification allows VIRTIO_BLK_F_MQ to be enabled when there is
|
||||||
|
|
|
@ -701,6 +701,11 @@ static void pci_hotplug(void *obj, void *data, QGuestAllocator *t_alloc)
|
||||||
QVirtioPCIDevice *dev;
|
QVirtioPCIDevice *dev;
|
||||||
QTestState *qts = dev1->pdev->bus->qts;
|
QTestState *qts = dev1->pdev->bus->qts;
|
||||||
|
|
||||||
|
if (dev1->pdev->bus->not_hotpluggable) {
|
||||||
|
g_test_skip("pci bus does not support hotplug");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* plug secondary disk */
|
/* plug secondary disk */
|
||||||
qtest_qmp_device_add(qts, "virtio-blk-pci", "drv1",
|
qtest_qmp_device_add(qts, "virtio-blk-pci", "drv1",
|
||||||
"{'addr': %s, 'drive': 'drive1'}",
|
"{'addr': %s, 'drive': 'drive1'}",
|
||||||
|
|
|
@ -173,6 +173,11 @@ static void hotplug(void *obj, void *data, QGuestAllocator *t_alloc)
|
||||||
QTestState *qts = dev->pdev->bus->qts;
|
QTestState *qts = dev->pdev->bus->qts;
|
||||||
const char *arch = qtest_get_arch();
|
const char *arch = qtest_get_arch();
|
||||||
|
|
||||||
|
if (dev->pdev->bus->not_hotpluggable) {
|
||||||
|
g_test_skip("pci bus does not support hotplug");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
qtest_qmp_device_add(qts, "virtio-net-pci", "net1",
|
qtest_qmp_device_add(qts, "virtio-net-pci", "net1",
|
||||||
"{'addr': %s}", stringify(PCI_SLOT_HP));
|
"{'addr': %s}", stringify(PCI_SLOT_HP));
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,11 @@ static void rng_hotplug(void *obj, void *data, QGuestAllocator *alloc)
|
||||||
QVirtioPCIDevice *dev = obj;
|
QVirtioPCIDevice *dev = obj;
|
||||||
QTestState *qts = dev->pdev->bus->qts;
|
QTestState *qts = dev->pdev->bus->qts;
|
||||||
|
|
||||||
|
if (dev->pdev->bus->not_hotpluggable) {
|
||||||
|
g_test_skip("pci bus does not support hotplug");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const char *arch = qtest_get_arch();
|
const char *arch = qtest_get_arch();
|
||||||
|
|
||||||
qtest_qmp_device_add(qts, "virtio-rng-pci", "rng1",
|
qtest_qmp_device_add(qts, "virtio-rng-pci", "rng1",
|
||||||
|
|
|
@ -221,7 +221,7 @@ static void gui_setup_refresh(DisplayState *ds)
|
||||||
void graphic_hw_update_done(QemuConsole *con)
|
void graphic_hw_update_done(QemuConsole *con)
|
||||||
{
|
{
|
||||||
if (con) {
|
if (con) {
|
||||||
qemu_co_queue_restart_all(&con->dump_queue);
|
qemu_co_enter_all(&con->dump_queue, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ softmmu_ss.add(pixman)
|
||||||
specific_ss.add(when: ['CONFIG_SOFTMMU'], if_true: pixman) # for the include path
|
specific_ss.add(when: ['CONFIG_SOFTMMU'], if_true: pixman) # for the include path
|
||||||
specific_ss.add(when: ['CONFIG_SOFTMMU'], if_true: opengl) # for the include path
|
specific_ss.add(when: ['CONFIG_SOFTMMU'], if_true: opengl) # for the include path
|
||||||
|
|
||||||
|
softmmu_ss.add(png)
|
||||||
softmmu_ss.add(files(
|
softmmu_ss.add(files(
|
||||||
'clipboard.c',
|
'clipboard.c',
|
||||||
'console.c',
|
'console.c',
|
||||||
|
@ -40,7 +41,7 @@ vnc_ss.add(files(
|
||||||
'vnc-jobs.c',
|
'vnc-jobs.c',
|
||||||
'vnc-clipboard.c',
|
'vnc-clipboard.c',
|
||||||
))
|
))
|
||||||
vnc_ss.add(zlib, png, jpeg, gnutls)
|
vnc_ss.add(zlib, jpeg, gnutls)
|
||||||
vnc_ss.add(when: sasl, if_true: files('vnc-auth-sasl.c'))
|
vnc_ss.add(when: sasl, if_true: files('vnc-auth-sasl.c'))
|
||||||
softmmu_ss.add_all(when: vnc, if_true: vnc_ss)
|
softmmu_ss.add_all(when: vnc, if_true: vnc_ss)
|
||||||
softmmu_ss.add(when: vnc, if_false: files('vnc-stubs.c'))
|
softmmu_ss.add(when: vnc, if_false: files('vnc-stubs.c'))
|
||||||
|
|
|
@ -67,34 +67,6 @@ void coroutine_fn qemu_co_queue_wait_impl(CoQueue *queue, QemuLockable *lock)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool qemu_co_queue_do_restart(CoQueue *queue, bool single)
|
|
||||||
{
|
|
||||||
Coroutine *next;
|
|
||||||
|
|
||||||
if (QSIMPLEQ_EMPTY(&queue->entries)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((next = QSIMPLEQ_FIRST(&queue->entries)) != NULL) {
|
|
||||||
QSIMPLEQ_REMOVE_HEAD(&queue->entries, co_queue_next);
|
|
||||||
aio_co_wake(next);
|
|
||||||
if (single) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool qemu_co_queue_next(CoQueue *queue)
|
|
||||||
{
|
|
||||||
return qemu_co_queue_do_restart(queue, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void qemu_co_queue_restart_all(CoQueue *queue)
|
|
||||||
{
|
|
||||||
qemu_co_queue_do_restart(queue, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool qemu_co_enter_next_impl(CoQueue *queue, QemuLockable *lock)
|
bool qemu_co_enter_next_impl(CoQueue *queue, QemuLockable *lock)
|
||||||
{
|
{
|
||||||
Coroutine *next;
|
Coroutine *next;
|
||||||
|
@ -115,6 +87,25 @@ bool qemu_co_enter_next_impl(CoQueue *queue, QemuLockable *lock)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool coroutine_fn qemu_co_queue_next(CoQueue *queue)
|
||||||
|
{
|
||||||
|
/* No unlock/lock needed in coroutine context. */
|
||||||
|
return qemu_co_enter_next_impl(queue, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void qemu_co_enter_all_impl(CoQueue *queue, QemuLockable *lock)
|
||||||
|
{
|
||||||
|
while (qemu_co_enter_next_impl(queue, lock)) {
|
||||||
|
/* just loop */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void coroutine_fn qemu_co_queue_restart_all(CoQueue *queue)
|
||||||
|
{
|
||||||
|
/* No unlock/lock needed in coroutine context. */
|
||||||
|
qemu_co_enter_all_impl(queue, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
bool qemu_co_queue_empty(CoQueue *queue)
|
bool qemu_co_queue_empty(CoQueue *queue)
|
||||||
{
|
{
|
||||||
return QSIMPLEQ_FIRST(&queue->entries) == NULL;
|
return QSIMPLEQ_FIRST(&queue->entries) == NULL;
|
||||||
|
|
Loading…
Reference in New Issue