aboutsummaryrefslogtreecommitdiff
path: root/hw/core
diff options
context:
space:
mode:
Diffstat (limited to 'hw/core')
-rw-r--r--hw/core/Kconfig4
-rw-r--r--hw/core/bus.c4
-rw-r--r--hw/core/clock.c38
-rw-r--r--hw/core/cpu-common.c143
-rw-r--r--hw/core/cpu-sysemu.c144
-rw-r--r--hw/core/cpu-system.c305
-rw-r--r--hw/core/cpu-user.c49
-rw-r--r--hw/core/eif.c709
-rw-r--r--hw/core/eif.h22
-rw-r--r--hw/core/generic-loader.c20
-rw-r--r--hw/core/gpio.c3
-rw-r--r--hw/core/guest-loader.c9
-rw-r--r--hw/core/irq.c42
-rw-r--r--hw/core/loader-fit.c42
-rw-r--r--hw/core/loader.c85
-rw-r--r--hw/core/machine-hmp-cmds.c4
-rw-r--r--hw/core/machine-qmp-cmds.c36
-rw-r--r--hw/core/machine-smp.c136
-rw-r--r--hw/core/machine.c297
-rw-r--r--hw/core/meson.build7
-rw-r--r--hw/core/null-machine.c3
-rw-r--r--hw/core/numa.c12
-rw-r--r--hw/core/or-irq.c7
-rw-r--r--hw/core/platform-bus.c10
-rw-r--r--hw/core/ptimer.c8
-rw-r--r--hw/core/qdev-clock.c86
-rw-r--r--hw/core/qdev-hotplug.c45
-rw-r--r--hw/core/qdev-properties-system.c242
-rw-r--r--hw/core/qdev-properties.c210
-rw-r--r--hw/core/qdev-user.c19
-rw-r--r--hw/core/qdev.c149
-rw-r--r--hw/core/register.c2
-rw-r--r--hw/core/reset.c9
-rw-r--r--hw/core/resetcontainer.c3
-rw-r--r--hw/core/resettable.c24
-rw-r--r--hw/core/split-irq.c5
-rw-r--r--hw/core/sysbus-fdt.c29
-rw-r--r--hw/core/sysbus.c75
-rw-r--r--hw/core/uboot_image.h2
-rw-r--r--hw/core/vm-change-state-handler.c20
40 files changed, 2227 insertions, 832 deletions
diff --git a/hw/core/Kconfig b/hw/core/Kconfig
index 24411f5..d1bdf76 100644
--- a/hw/core/Kconfig
+++ b/hw/core/Kconfig
@@ -34,3 +34,7 @@ config REGISTER
config SPLIT_IRQ
bool
+
+config EIF
+ bool
+ depends on LIBCBOR && GNUTLS
diff --git a/hw/core/bus.c b/hw/core/bus.c
index b9d8949..bddfc22 100644
--- a/hw/core/bus.c
+++ b/hw/core/bus.c
@@ -232,7 +232,7 @@ static char *default_bus_get_fw_dev_path(DeviceState *dev)
return g_strdup(object_get_typename(OBJECT(dev)));
}
-static void bus_class_init(ObjectClass *class, void *data)
+static void bus_class_init(ObjectClass *class, const void *data)
{
BusClass *bc = BUS_CLASS(class);
ResettableClass *rc = RESETTABLE_CLASS(class);
@@ -260,7 +260,7 @@ static const TypeInfo bus_info = {
.instance_init = qbus_initfn,
.instance_finalize = qbus_finalize,
.class_init = bus_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_RESETTABLE_INTERFACE },
{ }
},
diff --git a/hw/core/clock.c b/hw/core/clock.c
index e212865..9c90676 100644
--- a/hw/core/clock.c
+++ b/hw/core/clock.c
@@ -13,6 +13,8 @@
#include "qemu/osdep.h"
#include "qemu/cutils.h"
+#include "qapi/visitor.h"
+#include "system/qtest.h"
#include "hw/clock.h"
#include "trace.h"
@@ -42,16 +44,12 @@ Clock *clock_new(Object *parent, const char *name)
void clock_set_callback(Clock *clk, ClockCallback *cb, void *opaque,
unsigned int events)
{
+ assert(OBJECT(clk)->parent);
clk->callback = cb;
clk->callback_opaque = opaque;
clk->callback_events = events;
}
-void clock_clear_callback(Clock *clk)
-{
- clock_set_callback(clk, NULL, NULL, 0);
-}
-
bool clock_set(Clock *clk, uint64_t period)
{
if (clk->period == period) {
@@ -158,6 +156,25 @@ bool clock_set_mul_div(Clock *clk, uint32_t multiplier, uint32_t divider)
return true;
}
+static void clock_period_prop_get(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ Clock *clk = CLOCK(obj);
+ uint64_t period = clock_get(clk);
+ visit_type_uint64(v, name, &period, errp);
+}
+
+static void clock_unparent(Object *obj)
+{
+ /*
+ * Callback are registered by the parent, which might die anytime after
+ * it's unparented the children. Avoid having a callback to a deleted
+ * object in case the clock is still referenced somewhere else (eg: by
+ * a clock output).
+ */
+ clock_set_callback(CLOCK(obj), NULL, NULL, 0);
+}
+
static void clock_initfn(Object *obj)
{
Clock *clk = CLOCK(obj);
@@ -166,6 +183,11 @@ static void clock_initfn(Object *obj)
clk->divider = 1;
QLIST_INIT(&clk->children);
+
+ if (qtest_enabled()) {
+ object_property_add(obj, "qtest-clock-period", "uint64",
+ clock_period_prop_get, NULL, NULL, NULL);
+ }
}
static void clock_finalizefn(Object *obj)
@@ -184,11 +206,17 @@ static void clock_finalizefn(Object *obj)
g_free(clk->canonical_path);
}
+static void clock_class_init(ObjectClass *klass, const void *data)
+{
+ klass->unparent = clock_unparent;
+}
+
static const TypeInfo clock_info = {
.name = TYPE_CLOCK,
.parent = TYPE_OBJECT,
.instance_size = sizeof(Clock),
.instance_init = clock_initfn,
+ .class_init = clock_class_init,
.instance_finalize = clock_finalizefn,
};
diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c
index d2e3e45..39e674a 100644
--- a/hw/core/cpu-common.c
+++ b/hw/core/cpu-common.c
@@ -21,12 +21,16 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "hw/core/cpu.h"
-#include "sysemu/hw_accel.h"
+#include "system/hw_accel.h"
#include "qemu/log.h"
#include "qemu/main-loop.h"
+#include "qemu/lockcnt.h"
+#include "qemu/error-report.h"
+#include "qemu/qemu-print.h"
+#include "qemu/target-info.h"
#include "exec/log.h"
#include "exec/gdbstub.h"
-#include "sysemu/tcg.h"
+#include "system/tcg.h"
#include "hw/boards.h"
#include "hw/qdev-properties.h"
#include "trace.h"
@@ -39,9 +43,7 @@ CPUState *cpu_by_arch_id(int64_t id)
CPUState *cpu;
CPU_FOREACH(cpu) {
- CPUClass *cc = CPU_GET_CLASS(cpu);
-
- if (cc->get_arch_id(cpu) == id) {
+ if (cpu->cc->get_arch_id(cpu) == id) {
return cpu;
}
}
@@ -100,11 +102,9 @@ static int cpu_common_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg)
void cpu_dump_state(CPUState *cpu, FILE *f, int flags)
{
- CPUClass *cc = CPU_GET_CLASS(cpu);
-
- if (cc->dump_state) {
+ if (cpu->cc->dump_state) {
cpu_synchronize_state(cpu);
- cc->dump_state(cpu, f, flags);
+ cpu->cc->dump_state(cpu, f, flags);
}
}
@@ -118,11 +118,10 @@ void cpu_reset(CPUState *cpu)
static void cpu_common_reset_hold(Object *obj, ResetType type)
{
CPUState *cpu = CPU(obj);
- CPUClass *cc = CPU_GET_CLASS(cpu);
if (qemu_loglevel_mask(CPU_LOG_RESET)) {
qemu_log("CPU Reset (CPU %d)\n", cpu->cpu_index);
- log_cpu_state(cpu, cc->reset_dump_flags);
+ log_cpu_state(cpu, cpu->cc->reset_dump_flags);
}
cpu->interrupt_request = 0;
@@ -138,11 +137,6 @@ static void cpu_common_reset_hold(Object *obj, ResetType type)
cpu_exec_reset_hold(cpu);
}
-static bool cpu_common_has_work(CPUState *cs)
-{
- return false;
-}
-
ObjectClass *cpu_class_by_name(const char *typename, const char *cpu_model)
{
ObjectClass *oc;
@@ -161,6 +155,21 @@ ObjectClass *cpu_class_by_name(const char *typename, const char *cpu_model)
return NULL;
}
+char *cpu_model_from_type(const char *typename)
+{
+ g_autofree char *suffix = g_strdup_printf("-%s", target_cpu_type());
+
+ if (!object_class_by_name(typename)) {
+ return NULL;
+ }
+
+ if (g_str_has_suffix(typename, suffix)) {
+ return g_strndup(typename, strlen(typename) - strlen(suffix));
+ }
+
+ return g_strdup(typename);
+}
+
static void cpu_common_parse_features(const char *typename, char *features,
Error **errp)
{
@@ -192,6 +201,49 @@ static void cpu_common_parse_features(const char *typename, char *features,
}
}
+const char *parse_cpu_option(const char *cpu_option)
+{
+ ObjectClass *oc;
+ CPUClass *cc;
+ gchar **model_pieces;
+ const char *cpu_type;
+
+ model_pieces = g_strsplit(cpu_option, ",", 2);
+ if (!model_pieces[0]) {
+ error_report("-cpu option cannot be empty");
+ exit(1);
+ }
+
+ oc = cpu_class_by_name(target_cpu_type(), model_pieces[0]);
+ if (oc == NULL) {
+ error_report("unable to find CPU model '%s'", model_pieces[0]);
+ g_strfreev(model_pieces);
+ exit(EXIT_FAILURE);
+ }
+
+ cpu_type = object_class_get_name(oc);
+ cc = CPU_CLASS(oc);
+ cc->parse_features(cpu_type, model_pieces[1], &error_fatal);
+ g_strfreev(model_pieces);
+ return cpu_type;
+}
+
+bool cpu_exec_realizefn(CPUState *cpu, Error **errp)
+{
+ if (!accel_cpu_common_realize(cpu, errp)) {
+ return false;
+ }
+
+ gdb_init_cpu(cpu);
+
+ /* Wait until cpu initialization complete before exposing cpu. */
+ cpu_list_add(cpu);
+
+ cpu_vmstate_register(cpu);
+
+ return true;
+}
+
static void cpu_common_realizefn(DeviceState *dev, Error **errp)
{
CPUState *cpu = CPU(dev);
@@ -233,18 +285,34 @@ static void cpu_common_unrealizefn(DeviceState *dev)
cpu_exec_unrealizefn(cpu);
}
+void cpu_exec_unrealizefn(CPUState *cpu)
+{
+ cpu_vmstate_unregister(cpu);
+
+ cpu_list_remove(cpu);
+ /*
+ * Now that the vCPU has been removed from the RCU list, we can call
+ * accel_cpu_common_unrealize, which may free fields using call_rcu.
+ */
+ accel_cpu_common_unrealize(cpu);
+}
+
static void cpu_common_initfn(Object *obj)
{
CPUState *cpu = CPU(obj);
- gdb_init_cpu(cpu);
+ cpu_exec_class_post_init(CPU_GET_CLASS(obj));
+
+ /* cache the cpu class for the hotpath */
+ cpu->cc = CPU_GET_CLASS(cpu);
+
cpu->cpu_index = UNASSIGNED_CPU_INDEX;
cpu->cluster_index = UNASSIGNED_CLUSTER_INDEX;
+ cpu->as = NULL;
+ cpu->num_ases = 0;
/* user-mode doesn't have configurable SMP topology */
/* the default value is changed by qemu_init_vcpu() for system-mode */
- cpu->nr_cores = 1;
cpu->nr_threads = 1;
- cpu->cflags_next_tb = -1;
/* allocate storage for thread info, initialise condition variables */
cpu->thread = g_new0(QemuThread, 1);
@@ -282,7 +350,10 @@ static void cpu_common_finalize(Object *obj)
}
#endif
free_queued_cpu_work(cpu);
- g_array_free(cpu->gdb_regs, TRUE);
+ /* If cleanup didn't happen in context to gdb_unregister_coprocessor_all */
+ if (cpu->gdb_regs) {
+ g_array_free(cpu->gdb_regs, TRUE);
+ }
qemu_lockcnt_destroy(&cpu->in_ioctl_lock);
qemu_mutex_destroy(&cpu->work_mutex);
qemu_cond_destroy(cpu->halt_cond);
@@ -295,7 +366,7 @@ static int64_t cpu_common_get_arch_id(CPUState *cpu)
return cpu->cpu_index;
}
-static void cpu_common_class_init(ObjectClass *klass, void *data)
+static void cpu_common_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
@@ -303,7 +374,6 @@ static void cpu_common_class_init(ObjectClass *klass, void *data)
k->parse_features = cpu_common_parse_features;
k->get_arch_id = cpu_common_get_arch_id;
- k->has_work = cpu_common_has_work;
k->gdb_read_register = cpu_common_gdb_read_register;
k->gdb_write_register = cpu_common_gdb_write_register;
set_bit(DEVICE_CATEGORY_CPU, dc->categories);
@@ -335,3 +405,32 @@ static void cpu_register_types(void)
}
type_init(cpu_register_types)
+
+static void cpu_list_entry(gpointer data, gpointer user_data)
+{
+ CPUClass *cc = CPU_CLASS(OBJECT_CLASS(data));
+ const char *typename = object_class_get_name(OBJECT_CLASS(data));
+ g_autofree char *model = cpu_model_from_type(typename);
+
+ if (cc->deprecation_note) {
+ qemu_printf(" %s (deprecated)\n", model);
+ } else {
+ qemu_printf(" %s\n", model);
+ }
+}
+
+void list_cpus(void)
+{
+ CPUClass *cc = CPU_CLASS(object_class_by_name(target_cpu_type()));
+
+ if (cc->list_cpus) {
+ cc->list_cpus();
+ } else {
+ GSList *list;
+
+ list = object_class_get_list_sorted(TYPE_CPU, false);
+ qemu_printf("Available CPUs:\n");
+ g_slist_foreach(list, cpu_list_entry, NULL);
+ g_slist_free(list);
+ }
+}
diff --git a/hw/core/cpu-sysemu.c b/hw/core/cpu-sysemu.c
deleted file mode 100644
index 2a9a2a4..0000000
--- a/hw/core/cpu-sysemu.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * QEMU CPU model (system emulation specific)
- *
- * Copyright (c) 2012-2014 SUSE LINUX Products GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see
- * <http://www.gnu.org/licenses/gpl-2.0.html>
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "exec/tswap.h"
-#include "hw/core/sysemu-cpu-ops.h"
-
-bool cpu_paging_enabled(const CPUState *cpu)
-{
- CPUClass *cc = CPU_GET_CLASS(cpu);
-
- if (cc->sysemu_ops->get_paging_enabled) {
- return cc->sysemu_ops->get_paging_enabled(cpu);
- }
-
- return false;
-}
-
-bool cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list,
- Error **errp)
-{
- CPUClass *cc = CPU_GET_CLASS(cpu);
-
- if (cc->sysemu_ops->get_memory_mapping) {
- return cc->sysemu_ops->get_memory_mapping(cpu, list, errp);
- }
-
- error_setg(errp, "Obtaining memory mappings is unsupported on this CPU.");
- return false;
-}
-
-hwaddr cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr,
- MemTxAttrs *attrs)
-{
- CPUClass *cc = CPU_GET_CLASS(cpu);
-
- if (cc->sysemu_ops->get_phys_page_attrs_debug) {
- return cc->sysemu_ops->get_phys_page_attrs_debug(cpu, addr, attrs);
- }
- /* Fallback for CPUs which don't implement the _attrs_ hook */
- *attrs = MEMTXATTRS_UNSPECIFIED;
- return cc->sysemu_ops->get_phys_page_debug(cpu, addr);
-}
-
-hwaddr cpu_get_phys_page_debug(CPUState *cpu, vaddr addr)
-{
- MemTxAttrs attrs = {};
-
- return cpu_get_phys_page_attrs_debug(cpu, addr, &attrs);
-}
-
-int cpu_asidx_from_attrs(CPUState *cpu, MemTxAttrs attrs)
-{
- int ret = 0;
-
- if (cpu->cc->sysemu_ops->asidx_from_attrs) {
- ret = cpu->cc->sysemu_ops->asidx_from_attrs(cpu, attrs);
- assert(ret < cpu->num_ases && ret >= 0);
- }
- return ret;
-}
-
-int cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu,
- void *opaque)
-{
- CPUClass *cc = CPU_GET_CLASS(cpu);
-
- if (!cc->sysemu_ops->write_elf32_qemunote) {
- return 0;
- }
- return (*cc->sysemu_ops->write_elf32_qemunote)(f, cpu, opaque);
-}
-
-int cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cpu,
- int cpuid, void *opaque)
-{
- CPUClass *cc = CPU_GET_CLASS(cpu);
-
- if (!cc->sysemu_ops->write_elf32_note) {
- return -1;
- }
- return (*cc->sysemu_ops->write_elf32_note)(f, cpu, cpuid, opaque);
-}
-
-int cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cpu,
- void *opaque)
-{
- CPUClass *cc = CPU_GET_CLASS(cpu);
-
- if (!cc->sysemu_ops->write_elf64_qemunote) {
- return 0;
- }
- return (*cc->sysemu_ops->write_elf64_qemunote)(f, cpu, opaque);
-}
-
-int cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu,
- int cpuid, void *opaque)
-{
- CPUClass *cc = CPU_GET_CLASS(cpu);
-
- if (!cc->sysemu_ops->write_elf64_note) {
- return -1;
- }
- return (*cc->sysemu_ops->write_elf64_note)(f, cpu, cpuid, opaque);
-}
-
-bool cpu_virtio_is_big_endian(CPUState *cpu)
-{
- CPUClass *cc = CPU_GET_CLASS(cpu);
-
- if (cc->sysemu_ops->virtio_is_big_endian) {
- return cc->sysemu_ops->virtio_is_big_endian(cpu);
- }
- return target_words_bigendian();
-}
-
-GuestPanicInformation *cpu_get_crash_info(CPUState *cpu)
-{
- CPUClass *cc = CPU_GET_CLASS(cpu);
- GuestPanicInformation *res = NULL;
-
- if (cc->sysemu_ops->get_crash_info) {
- res = cc->sysemu_ops->get_crash_info(cpu);
- }
- return res;
-}
diff --git a/hw/core/cpu-system.c b/hw/core/cpu-system.c
new file mode 100644
index 0000000..3c84176
--- /dev/null
+++ b/hw/core/cpu-system.c
@@ -0,0 +1,305 @@
+/*
+ * QEMU CPU model (system specific)
+ *
+ * Copyright (c) 2012-2014 SUSE LINUX Products GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/gpl-2.0.html>
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "system/address-spaces.h"
+#include "exec/cputlb.h"
+#include "system/memory.h"
+#include "exec/tb-flush.h"
+#include "exec/tswap.h"
+#include "hw/qdev-core.h"
+#include "hw/qdev-properties.h"
+#include "hw/core/sysemu-cpu-ops.h"
+#include "migration/vmstate.h"
+#include "system/tcg.h"
+
+bool cpu_has_work(CPUState *cpu)
+{
+ return cpu->cc->sysemu_ops->has_work(cpu);
+}
+
+bool cpu_paging_enabled(const CPUState *cpu)
+{
+ if (cpu->cc->sysemu_ops->get_paging_enabled) {
+ return cpu->cc->sysemu_ops->get_paging_enabled(cpu);
+ }
+
+ return false;
+}
+
+bool cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list,
+ Error **errp)
+{
+ if (cpu->cc->sysemu_ops->get_memory_mapping) {
+ return cpu->cc->sysemu_ops->get_memory_mapping(cpu, list, errp);
+ }
+
+ error_setg(errp, "Obtaining memory mappings is unsupported on this CPU.");
+ return false;
+}
+
+hwaddr cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr,
+ MemTxAttrs *attrs)
+{
+ hwaddr paddr;
+
+ if (cpu->cc->sysemu_ops->get_phys_page_attrs_debug) {
+ paddr = cpu->cc->sysemu_ops->get_phys_page_attrs_debug(cpu, addr,
+ attrs);
+ } else {
+ /* Fallback for CPUs which don't implement the _attrs_ hook */
+ *attrs = MEMTXATTRS_UNSPECIFIED;
+ paddr = cpu->cc->sysemu_ops->get_phys_page_debug(cpu, addr);
+ }
+ /* Indicate that this is a debug access. */
+ attrs->debug = 1;
+ return paddr;
+}
+
+hwaddr cpu_get_phys_page_debug(CPUState *cpu, vaddr addr)
+{
+ MemTxAttrs attrs = {};
+
+ return cpu_get_phys_page_attrs_debug(cpu, addr, &attrs);
+}
+
+int cpu_asidx_from_attrs(CPUState *cpu, MemTxAttrs attrs)
+{
+ int ret = 0;
+
+ if (cpu->cc->sysemu_ops->asidx_from_attrs) {
+ ret = cpu->cc->sysemu_ops->asidx_from_attrs(cpu, attrs);
+ assert(ret < cpu->num_ases && ret >= 0);
+ }
+ return ret;
+}
+
+int cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu,
+ void *opaque)
+{
+ if (!cpu->cc->sysemu_ops->write_elf32_qemunote) {
+ return 0;
+ }
+ return (*cpu->cc->sysemu_ops->write_elf32_qemunote)(f, cpu, opaque);
+}
+
+int cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cpu,
+ int cpuid, void *opaque)
+{
+ if (!cpu->cc->sysemu_ops->write_elf32_note) {
+ return -1;
+ }
+ return (*cpu->cc->sysemu_ops->write_elf32_note)(f, cpu, cpuid, opaque);
+}
+
+int cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cpu,
+ void *opaque)
+{
+ if (!cpu->cc->sysemu_ops->write_elf64_qemunote) {
+ return 0;
+ }
+ return (*cpu->cc->sysemu_ops->write_elf64_qemunote)(f, cpu, opaque);
+}
+
+int cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu,
+ int cpuid, void *opaque)
+{
+ if (!cpu->cc->sysemu_ops->write_elf64_note) {
+ return -1;
+ }
+ return (*cpu->cc->sysemu_ops->write_elf64_note)(f, cpu, cpuid, opaque);
+}
+
+bool cpu_virtio_is_big_endian(CPUState *cpu)
+{
+ if (cpu->cc->sysemu_ops->virtio_is_big_endian) {
+ return cpu->cc->sysemu_ops->virtio_is_big_endian(cpu);
+ }
+ return target_big_endian();
+}
+
+GuestPanicInformation *cpu_get_crash_info(CPUState *cpu)
+{
+ GuestPanicInformation *res = NULL;
+
+ if (cpu->cc->sysemu_ops->get_crash_info) {
+ res = cpu->cc->sysemu_ops->get_crash_info(cpu);
+ }
+ return res;
+}
+
+static const Property cpu_system_props[] = {
+ /*
+ * Create a memory property for system CPU object, so users can
+ * wire up its memory. The default if no link is set up is to use
+ * the system address space.
+ */
+ DEFINE_PROP_LINK("memory", CPUState, memory, TYPE_MEMORY_REGION,
+ MemoryRegion *),
+};
+
+static bool cpu_get_start_powered_off(Object *obj, Error **errp)
+{
+ CPUState *cpu = CPU(obj);
+ return cpu->start_powered_off;
+}
+
+static void cpu_set_start_powered_off(Object *obj, bool value, Error **errp)
+{
+ CPUState *cpu = CPU(obj);
+ cpu->start_powered_off = value;
+}
+
+void cpu_class_init_props(DeviceClass *dc)
+{
+ ObjectClass *oc = OBJECT_CLASS(dc);
+
+ /*
+ * We can't use DEFINE_PROP_BOOL in the Property array for this
+ * property, because we want this to be settable after realize.
+ */
+ object_class_property_add_bool(oc, "start-powered-off",
+ cpu_get_start_powered_off,
+ cpu_set_start_powered_off);
+
+ device_class_set_props(dc, cpu_system_props);
+}
+
+void cpu_exec_class_post_init(CPUClass *cc)
+{
+ /* Check mandatory SysemuCPUOps handlers */
+ g_assert(cc->sysemu_ops->has_work);
+}
+
+void cpu_exec_initfn(CPUState *cpu)
+{
+ cpu->memory = get_system_memory();
+ object_ref(OBJECT(cpu->memory));
+}
+
+static int cpu_common_post_load(void *opaque, int version_id)
+{
+ if (tcg_enabled()) {
+ CPUState *cpu = opaque;
+
+ /*
+ * 0x01 was CPU_INTERRUPT_EXIT. This line can be removed when the
+ * version_id is increased.
+ */
+ cpu->interrupt_request &= ~0x01;
+
+ tlb_flush(cpu);
+
+ /*
+ * loadvm has just updated the content of RAM, bypassing the
+ * usual mechanisms that ensure we flush TBs for writes to
+ * memory we've translated code from. So we must flush all TBs,
+ * which will now be stale.
+ */
+ tb_flush(cpu);
+ }
+
+ return 0;
+}
+
+static int cpu_common_pre_load(void *opaque)
+{
+ CPUState *cpu = opaque;
+
+ cpu->exception_index = -1;
+
+ return 0;
+}
+
+static bool cpu_common_exception_index_needed(void *opaque)
+{
+ CPUState *cpu = opaque;
+
+ return tcg_enabled() && cpu->exception_index != -1;
+}
+
+static const VMStateDescription vmstate_cpu_common_exception_index = {
+ .name = "cpu_common/exception_index",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = cpu_common_exception_index_needed,
+ .fields = (const VMStateField[]) {
+ VMSTATE_INT32(exception_index, CPUState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static bool cpu_common_crash_occurred_needed(void *opaque)
+{
+ CPUState *cpu = opaque;
+
+ return cpu->crash_occurred;
+}
+
+static const VMStateDescription vmstate_cpu_common_crash_occurred = {
+ .name = "cpu_common/crash_occurred",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = cpu_common_crash_occurred_needed,
+ .fields = (const VMStateField[]) {
+ VMSTATE_BOOL(crash_occurred, CPUState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+const VMStateDescription vmstate_cpu_common = {
+ .name = "cpu_common",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .pre_load = cpu_common_pre_load,
+ .post_load = cpu_common_post_load,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32(halted, CPUState),
+ VMSTATE_UINT32(interrupt_request, CPUState),
+ VMSTATE_END_OF_LIST()
+ },
+ .subsections = (const VMStateDescription * const []) {
+ &vmstate_cpu_common_exception_index,
+ &vmstate_cpu_common_crash_occurred,
+ NULL
+ }
+};
+
+void cpu_vmstate_register(CPUState *cpu)
+{
+ if (qdev_get_vmsd(DEVICE(cpu)) == NULL) {
+ vmstate_register(NULL, cpu->cpu_index, &vmstate_cpu_common, cpu);
+ }
+ if (cpu->cc->sysemu_ops->legacy_vmsd != NULL) {
+ vmstate_register(NULL, cpu->cpu_index,
+ cpu->cc->sysemu_ops->legacy_vmsd, cpu);
+ }
+}
+
+void cpu_vmstate_unregister(CPUState *cpu)
+{
+ if (cpu->cc->sysemu_ops->legacy_vmsd != NULL) {
+ vmstate_unregister(NULL, cpu->cc->sysemu_ops->legacy_vmsd, cpu);
+ }
+ if (qdev_get_vmsd(DEVICE(cpu)) == NULL) {
+ vmstate_unregister(NULL, &vmstate_cpu_common, cpu);
+ }
+}
diff --git a/hw/core/cpu-user.c b/hw/core/cpu-user.c
new file mode 100644
index 0000000..7176791
--- /dev/null
+++ b/hw/core/cpu-user.c
@@ -0,0 +1,49 @@
+/*
+ * QEMU CPU model (user specific)
+ *
+ * Copyright (c) Linaro, Ltd.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/qdev-core.h"
+#include "hw/qdev-properties.h"
+#include "hw/core/cpu.h"
+#include "migration/vmstate.h"
+
+static const Property cpu_user_props[] = {
+ /*
+ * Create a property for the user-only object, so users can
+ * adjust prctl(PR_SET_UNALIGN) from the command-line.
+ * Has no effect if the target does not support the feature.
+ */
+ DEFINE_PROP_BOOL("prctl-unalign-sigbus", CPUState,
+ prctl_unalign_sigbus, false),
+};
+
+void cpu_class_init_props(DeviceClass *dc)
+{
+ device_class_set_props(dc, cpu_user_props);
+}
+
+void cpu_exec_class_post_init(CPUClass *cc)
+{
+ /* nothing to do */
+}
+
+void cpu_exec_initfn(CPUState *cpu)
+{
+ /* nothing to do */
+}
+
+void cpu_vmstate_register(CPUState *cpu)
+{
+ assert(qdev_get_vmsd(DEVICE(cpu)) == NULL ||
+ qdev_get_vmsd(DEVICE(cpu))->unmigratable);
+}
+
+void cpu_vmstate_unregister(CPUState *cpu)
+{
+ /* nothing to do */
+}
diff --git a/hw/core/eif.c b/hw/core/eif.c
new file mode 100644
index 0000000..513caec
--- /dev/null
+++ b/hw/core/eif.c
@@ -0,0 +1,709 @@
+/*
+ * EIF (Enclave Image Format) related helpers
+ *
+ * Copyright (c) 2024 Dorjoy Chowdhury <dorjoychy111@gmail.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version. See the COPYING file in the
+ * top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/bswap.h"
+#include "qapi/error.h"
+#include "crypto/hash.h"
+#include "crypto/x509-utils.h"
+#include <zlib.h> /* for crc32 */
+#include <cbor.h>
+
+#include "hw/core/eif.h"
+
+#define MAX_SECTIONS 32
+
+/* members are ordered according to field order in .eif file */
+typedef struct EifHeader {
+ uint8_t magic[4]; /* must be .eif in ascii i.e., [46, 101, 105, 102] */
+ uint16_t version;
+ uint16_t flags;
+ uint64_t default_memory;
+ uint64_t default_cpus;
+ uint16_t reserved;
+ uint16_t section_cnt;
+ uint64_t section_offsets[MAX_SECTIONS];
+ uint64_t section_sizes[MAX_SECTIONS];
+ uint32_t unused;
+ uint32_t eif_crc32;
+} QEMU_PACKED EifHeader;
+
+/* members are ordered according to field order in .eif file */
+typedef struct EifSectionHeader {
+ /*
+ * 0 = invalid, 1 = kernel, 2 = cmdline, 3 = ramdisk, 4 = signature,
+ * 5 = metadata
+ */
+ uint16_t section_type;
+ uint16_t flags;
+ uint64_t section_size;
+} QEMU_PACKED EifSectionHeader;
+
+enum EifSectionTypes {
+ EIF_SECTION_INVALID = 0,
+ EIF_SECTION_KERNEL = 1,
+ EIF_SECTION_CMDLINE = 2,
+ EIF_SECTION_RAMDISK = 3,
+ EIF_SECTION_SIGNATURE = 4,
+ EIF_SECTION_METADATA = 5,
+ EIF_SECTION_MAX = 6,
+};
+
+static const char *section_type_to_string(uint16_t type)
+{
+ const char *str;
+ switch (type) {
+ case EIF_SECTION_INVALID:
+ str = "invalid";
+ break;
+ case EIF_SECTION_KERNEL:
+ str = "kernel";
+ break;
+ case EIF_SECTION_CMDLINE:
+ str = "cmdline";
+ break;
+ case EIF_SECTION_RAMDISK:
+ str = "ramdisk";
+ break;
+ case EIF_SECTION_SIGNATURE:
+ str = "signature";
+ break;
+ case EIF_SECTION_METADATA:
+ str = "metadata";
+ break;
+ default:
+ str = "unknown";
+ break;
+ }
+
+ return str;
+}
+
+static bool read_eif_header(FILE *f, EifHeader *header, uint32_t *crc,
+ Error **errp)
+{
+ size_t got;
+ size_t header_size = sizeof(*header);
+
+ got = fread(header, 1, header_size, f);
+ if (got != header_size) {
+ error_setg(errp, "Failed to read EIF header");
+ return false;
+ }
+
+ if (memcmp(header->magic, ".eif", 4) != 0) {
+ error_setg(errp, "Invalid EIF image. Magic mismatch.");
+ return false;
+ }
+
+ /* Exclude header->eif_crc32 field from CRC calculation */
+ *crc = crc32(*crc, (uint8_t *)header, header_size - 4);
+
+ header->version = be16_to_cpu(header->version);
+ header->flags = be16_to_cpu(header->flags);
+ header->default_memory = be64_to_cpu(header->default_memory);
+ header->default_cpus = be64_to_cpu(header->default_cpus);
+ header->reserved = be16_to_cpu(header->reserved);
+ header->section_cnt = be16_to_cpu(header->section_cnt);
+
+ for (int i = 0; i < MAX_SECTIONS; ++i) {
+ header->section_offsets[i] = be64_to_cpu(header->section_offsets[i]);
+ }
+
+ for (int i = 0; i < MAX_SECTIONS; ++i) {
+ header->section_sizes[i] = be64_to_cpu(header->section_sizes[i]);
+ if (header->section_sizes[i] > SSIZE_MAX) {
+ error_setg(errp, "Invalid EIF image. Section size out of bounds");
+ return false;
+ }
+ }
+
+ header->unused = be32_to_cpu(header->unused);
+ header->eif_crc32 = be32_to_cpu(header->eif_crc32);
+ return true;
+}
+
+static bool read_eif_section_header(FILE *f, EifSectionHeader *section_header,
+ uint32_t *crc, Error **errp)
+{
+ size_t got;
+ size_t section_header_size = sizeof(*section_header);
+
+ got = fread(section_header, 1, section_header_size, f);
+ if (got != section_header_size) {
+ error_setg(errp, "Failed to read EIF section header");
+ return false;
+ }
+
+ *crc = crc32(*crc, (uint8_t *)section_header, section_header_size);
+
+ section_header->section_type = be16_to_cpu(section_header->section_type);
+ section_header->flags = be16_to_cpu(section_header->flags);
+ section_header->section_size = be64_to_cpu(section_header->section_size);
+ return true;
+}
+
+/*
+ * Upon success, the caller is responsible for unlinking and freeing *tmp_path.
+ */
+static bool get_tmp_file(const char *template, char **tmp_path, Error **errp)
+{
+ int tmp_fd;
+
+ *tmp_path = NULL;
+ tmp_fd = g_file_open_tmp(template, tmp_path, NULL);
+ if (tmp_fd < 0 || *tmp_path == NULL) {
+ error_setg(errp, "Failed to create temporary file for template %s",
+ template);
+ return false;
+ }
+
+ close(tmp_fd);
+ return true;
+}
+
+static void safe_fclose(FILE *f)
+{
+ if (f) {
+ fclose(f);
+ }
+}
+
+static void safe_unlink(char *f)
+{
+ if (f) {
+ unlink(f);
+ }
+}
+
+/*
+ * Upon success, the caller is reponsible for unlinking and freeing *kernel_path
+ */
+static bool read_eif_kernel(FILE *f, uint64_t size, char **kernel_path,
+ QCryptoHash *hash0, QCryptoHash *hash1,
+ uint32_t *crc, Error **errp)
+{
+ size_t got;
+ FILE *tmp_file = NULL;
+ uint8_t *kernel = g_try_malloc(size);
+ if (!kernel) {
+ error_setg(errp, "Out of memory reading kernel section");
+ goto cleanup;
+ }
+
+ *kernel_path = NULL;
+ if (!get_tmp_file("eif-kernel-XXXXXX", kernel_path, errp)) {
+ goto cleanup;
+ }
+
+ tmp_file = fopen(*kernel_path, "wb");
+ if (tmp_file == NULL) {
+ error_setg_errno(errp, errno, "Failed to open temporary file %s",
+ *kernel_path);
+ goto cleanup;
+ }
+
+ got = fread(kernel, 1, size, f);
+ if ((uint64_t) got != size) {
+ error_setg(errp, "Failed to read EIF kernel section data");
+ goto cleanup;
+ }
+
+ got = fwrite(kernel, 1, size, tmp_file);
+ if ((uint64_t) got != size) {
+ error_setg(errp, "Failed to write EIF kernel section data to temporary"
+ " file");
+ goto cleanup;
+ }
+
+ *crc = crc32(*crc, kernel, size);
+ if (qcrypto_hash_update(hash0, (char *)kernel, size, errp) != 0 ||
+ qcrypto_hash_update(hash1, (char *)kernel, size, errp) != 0) {
+ goto cleanup;
+ }
+ g_free(kernel);
+ fclose(tmp_file);
+
+ return true;
+
+ cleanup:
+ safe_fclose(tmp_file);
+
+ safe_unlink(*kernel_path);
+ g_free(*kernel_path);
+ *kernel_path = NULL;
+
+ g_free(kernel);
+ return false;
+}
+
+static bool read_eif_cmdline(FILE *f, uint64_t size, char *cmdline,
+ QCryptoHash *hash0, QCryptoHash *hash1,
+ uint32_t *crc, Error **errp)
+{
+ size_t got = fread(cmdline, 1, size, f);
+ if ((uint64_t) got != size) {
+ error_setg(errp, "Failed to read EIF cmdline section data");
+ return false;
+ }
+
+ *crc = crc32(*crc, (uint8_t *)cmdline, size);
+ if (qcrypto_hash_update(hash0, cmdline, size, errp) != 0 ||
+ qcrypto_hash_update(hash1, cmdline, size, errp) != 0) {
+ return false;
+ }
+ return true;
+}
+
+static bool read_eif_ramdisk(FILE *eif, FILE *initrd, uint64_t size,
+ QCryptoHash *hash0, QCryptoHash *h, uint32_t *crc,
+ Error **errp)
+{
+ size_t got;
+ bool ret = false;
+ uint8_t *ramdisk = g_try_malloc(size);
+ if (!ramdisk) {
+ error_setg(errp, "Out of memory reading initrd section");
+ goto cleanup;
+ }
+
+ got = fread(ramdisk, 1, size, eif);
+ if ((uint64_t) got != size) {
+ error_setg(errp, "Failed to read EIF ramdisk section data");
+ goto cleanup;
+ }
+
+ got = fwrite(ramdisk, 1, size, initrd);
+ if ((uint64_t) got != size) {
+ error_setg(errp, "Failed to write EIF ramdisk data to temporary file");
+ goto cleanup;
+ }
+
+ *crc = crc32(*crc, ramdisk, size);
+ if (qcrypto_hash_update(hash0, (char *)ramdisk, size, errp) != 0 ||
+ qcrypto_hash_update(h, (char *)ramdisk, size, errp) != 0) {
+ goto cleanup;
+ }
+ ret = true;
+
+ cleanup:
+ g_free(ramdisk);
+ return ret;
+}
+
+static bool get_signature_fingerprint_sha384(FILE *eif, uint64_t size,
+ uint8_t *sha384,
+ uint32_t *crc,
+ Error **errp)
+{
+ size_t got;
+ g_autofree uint8_t *sig = NULL;
+ g_autofree uint8_t *cert = NULL;
+ cbor_item_t *item = NULL;
+ cbor_item_t *pcr0 = NULL;
+ size_t len;
+ size_t hash_len = QCRYPTO_HASH_DIGEST_LEN_SHA384;
+ struct cbor_pair *pair;
+ struct cbor_load_result result;
+ bool ret = false;
+
+ sig = g_try_malloc(size);
+ if (!sig) {
+ error_setg(errp, "Out of memory reading signature section");
+ goto cleanup;
+ }
+
+ got = fread(sig, 1, size, eif);
+ if ((uint64_t) got != size) {
+ error_setg(errp, "Failed to read EIF signature section data");
+ goto cleanup;
+ }
+
+ *crc = crc32(*crc, sig, size);
+
+ item = cbor_load(sig, size, &result);
+ if (!item || result.error.code != CBOR_ERR_NONE) {
+ error_setg(errp, "Failed to load signature section data as CBOR");
+ goto cleanup;
+ }
+ if (!cbor_isa_array(item) || cbor_array_size(item) < 1) {
+ error_setg(errp, "Invalid signature CBOR");
+ goto cleanup;
+ }
+ pcr0 = cbor_array_get(item, 0);
+ if (!pcr0) {
+ error_setg(errp, "Failed to get PCR0 signature");
+ goto cleanup;
+ }
+ if (!cbor_isa_map(pcr0) || cbor_map_size(pcr0) != 2) {
+ error_setg(errp, "Invalid signature CBOR");
+ goto cleanup;
+ }
+ pair = cbor_map_handle(pcr0);
+ if (!cbor_isa_string(pair->key) || cbor_string_length(pair->key) != 19 ||
+ memcmp(cbor_string_handle(pair->key), "signing_certificate", 19) != 0) {
+ error_setg(errp, "Invalid signautre CBOR");
+ goto cleanup;
+ }
+ if (!cbor_isa_array(pair->value)) {
+ error_setg(errp, "Invalid signature CBOR");
+ goto cleanup;
+ }
+ len = cbor_array_size(pair->value);
+ if (len == 0) {
+ error_setg(errp, "Invalid signature CBOR");
+ goto cleanup;
+ }
+ cert = g_try_malloc(len);
+ if (!cert) {
+ error_setg(errp, "Out of memory reading signature section");
+ goto cleanup;
+ }
+
+ for (int i = 0; i < len; ++i) {
+ cbor_item_t *tmp = cbor_array_get(pair->value, i);
+ if (!tmp) {
+ error_setg(errp, "Invalid signature CBOR");
+ goto cleanup;
+ }
+ if (!cbor_isa_uint(tmp) || cbor_int_get_width(tmp) != CBOR_INT_8) {
+ cbor_decref(&tmp);
+ error_setg(errp, "Invalid signature CBOR");
+ goto cleanup;
+ }
+ cert[i] = cbor_get_uint8(tmp);
+ cbor_decref(&tmp);
+ }
+
+ if (qcrypto_get_x509_cert_fingerprint(cert, len, QCRYPTO_HASH_ALGO_SHA384,
+ sha384, &hash_len, errp)) {
+ goto cleanup;
+ }
+
+ ret = true;
+
+ cleanup:
+ if (pcr0) {
+ cbor_decref(&pcr0);
+ }
+ if (item) {
+ cbor_decref(&item);
+ }
+ return ret;
+}
+
+/* Expects file to have offset 0 before this function is called */
+static long get_file_size(FILE *f, Error **errp)
+{
+ long size;
+
+ if (fseek(f, 0, SEEK_END) != 0) {
+ error_setg_errno(errp, errno, "Failed to seek to the end of file");
+ return -1;
+ }
+
+ size = ftell(f);
+ if (size == -1) {
+ error_setg_errno(errp, errno, "Failed to get offset");
+ return -1;
+ }
+
+ if (fseek(f, 0, SEEK_SET) != 0) {
+ error_setg_errno(errp, errno, "Failed to seek back to the start");
+ return -1;
+ }
+
+ return size;
+}
+
+static bool get_SHA384_hash(QCryptoHash *h, uint8_t *hash, Error **errp)
+{
+ size_t hash_len = QCRYPTO_HASH_DIGEST_LEN_SHA384;
+ return qcrypto_hash_finalize_bytes(h, &hash, &hash_len, errp) == 0;
+}
+
+/*
+ * Upon success, the caller is reponsible for unlinking and freeing
+ * *kernel_path, *initrd_path and freeing *cmdline.
+ */
+bool read_eif_file(const char *eif_path, const char *machine_initrd,
+ char **kernel_path, char **initrd_path, char **cmdline,
+ uint8_t *image_hash, uint8_t *bootstrap_hash,
+ uint8_t *app_hash, uint8_t *fingerprint_hash,
+ bool *signature_found, Error **errp)
+{
+ FILE *f = NULL;
+ FILE *machine_initrd_f = NULL;
+ FILE *initrd_path_f = NULL;
+ long machine_initrd_size;
+ uint32_t crc = 0;
+ EifHeader eif_header;
+ bool seen_sections[EIF_SECTION_MAX] = {false};
+ /* kernel + ramdisks + cmdline SHA384 hash */
+ g_autoptr(QCryptoHash) hash0 = NULL;
+ /* kernel + boot ramdisk + cmdline SHA384 hash */
+ g_autoptr(QCryptoHash) hash1 = NULL;
+ /* application ramdisk(s) SHA384 hash */
+ g_autoptr(QCryptoHash) hash2 = NULL;
+
+ *signature_found = false;
+ *kernel_path = *initrd_path = *cmdline = NULL;
+
+ hash0 = qcrypto_hash_new(QCRYPTO_HASH_ALGO_SHA384, errp);
+ if (!hash0) {
+ goto cleanup;
+ }
+ hash1 = qcrypto_hash_new(QCRYPTO_HASH_ALGO_SHA384, errp);
+ if (!hash1) {
+ goto cleanup;
+ }
+ hash2 = qcrypto_hash_new(QCRYPTO_HASH_ALGO_SHA384, errp);
+ if (!hash2) {
+ goto cleanup;
+ }
+
+ f = fopen(eif_path, "rb");
+ if (f == NULL) {
+ error_setg_errno(errp, errno, "Failed to open %s", eif_path);
+ goto cleanup;
+ }
+
+ if (!read_eif_header(f, &eif_header, &crc, errp)) {
+ goto cleanup;
+ }
+
+ if (eif_header.version < 4) {
+ error_setg(errp, "Expected EIF version 4 or greater");
+ goto cleanup;
+ }
+
+ if (eif_header.flags != 0) {
+ error_setg(errp, "Expected EIF flags to be 0");
+ goto cleanup;
+ }
+
+ if (eif_header.section_cnt > MAX_SECTIONS) {
+ error_setg(errp, "EIF header section count must not be greater than "
+ "%d but found %d", MAX_SECTIONS, eif_header.section_cnt);
+ goto cleanup;
+ }
+
+ for (int i = 0; i < eif_header.section_cnt; ++i) {
+ EifSectionHeader hdr;
+ uint16_t section_type;
+
+ if (eif_header.section_offsets[i] > OFF_MAX) {
+ error_setg(errp, "Invalid EIF image. Section offset out of bounds");
+ goto cleanup;
+ }
+ if (fseek(f, eif_header.section_offsets[i], SEEK_SET) != 0) {
+ error_setg_errno(errp, errno, "Failed to offset to %" PRIu64 " in EIF file",
+ eif_header.section_offsets[i]);
+ goto cleanup;
+ }
+
+ if (!read_eif_section_header(f, &hdr, &crc, errp)) {
+ goto cleanup;
+ }
+
+ if (hdr.flags != 0) {
+ error_setg(errp, "Expected EIF section header flags to be 0");
+ goto cleanup;
+ }
+
+ if (eif_header.section_sizes[i] != hdr.section_size) {
+ error_setg(errp, "EIF section size mismatch between header and "
+ "section header: header %" PRIu64 ", section header %" PRIu64,
+ eif_header.section_sizes[i],
+ hdr.section_size);
+ goto cleanup;
+ }
+
+ section_type = hdr.section_type;
+
+ switch (section_type) {
+ case EIF_SECTION_KERNEL:
+ if (seen_sections[EIF_SECTION_KERNEL]) {
+ error_setg(errp, "Invalid EIF image. More than 1 kernel "
+ "section");
+ goto cleanup;
+ }
+
+ if (!read_eif_kernel(f, hdr.section_size, kernel_path, hash0,
+ hash1, &crc, errp)) {
+ goto cleanup;
+ }
+
+ break;
+ case EIF_SECTION_CMDLINE:
+ {
+ uint64_t size;
+ if (seen_sections[EIF_SECTION_CMDLINE]) {
+ error_setg(errp, "Invalid EIF image. More than 1 cmdline "
+ "section");
+ goto cleanup;
+ }
+ size = hdr.section_size;
+ *cmdline = g_try_malloc(size + 1);
+ if (!*cmdline) {
+ error_setg(errp, "Out of memory reading command line section");
+ goto cleanup;
+ }
+ if (!read_eif_cmdline(f, size, *cmdline, hash0, hash1, &crc,
+ errp)) {
+ goto cleanup;
+ }
+ (*cmdline)[size] = '\0';
+
+ break;
+ }
+ case EIF_SECTION_RAMDISK:
+ {
+ QCryptoHash *h = hash2;
+ if (!seen_sections[EIF_SECTION_RAMDISK]) {
+ /*
+ * If this is the first time we are seeing a ramdisk section,
+ * we need to:
+ * 1) hash it into bootstrap (hash1) instead of app (hash2)
+ * along with image (hash0)
+ * 2) create the initrd temporary file.
+ */
+ h = hash1;
+ if (!get_tmp_file("eif-initrd-XXXXXX", initrd_path, errp)) {
+ goto cleanup;
+ }
+ initrd_path_f = fopen(*initrd_path, "wb");
+ if (initrd_path_f == NULL) {
+ error_setg_errno(errp, errno, "Failed to open file %s",
+ *initrd_path);
+ goto cleanup;
+ }
+ }
+
+ if (!read_eif_ramdisk(f, initrd_path_f, hdr.section_size, hash0, h,
+ &crc, errp)) {
+ goto cleanup;
+ }
+
+ break;
+ }
+ case EIF_SECTION_SIGNATURE:
+ *signature_found = true;
+ if (!get_signature_fingerprint_sha384(f, hdr.section_size,
+ fingerprint_hash, &crc,
+ errp)) {
+ goto cleanup;
+ }
+ break;
+ default:
+ /* other sections including invalid or unknown sections */
+ {
+ uint8_t *buf;
+ size_t got;
+ uint64_t size = hdr.section_size;
+ buf = g_try_malloc(size);
+ if (!buf) {
+ error_setg(errp, "Out of memory reading unknown section");
+ goto cleanup;
+ }
+ got = fread(buf, 1, size, f);
+ if ((uint64_t) got != size) {
+ g_free(buf);
+ error_setg(errp, "Failed to read EIF %s section data",
+ section_type_to_string(section_type));
+ goto cleanup;
+ }
+ crc = crc32(crc, buf, size);
+ g_free(buf);
+ break;
+ }
+ }
+
+ if (section_type < EIF_SECTION_MAX) {
+ seen_sections[section_type] = true;
+ }
+ }
+
+ if (!seen_sections[EIF_SECTION_KERNEL]) {
+ error_setg(errp, "Invalid EIF image. No kernel section.");
+ goto cleanup;
+ }
+ if (!seen_sections[EIF_SECTION_CMDLINE]) {
+ error_setg(errp, "Invalid EIF image. No cmdline section.");
+ goto cleanup;
+ }
+ if (!seen_sections[EIF_SECTION_RAMDISK]) {
+ error_setg(errp, "Invalid EIF image. No ramdisk section.");
+ goto cleanup;
+ }
+
+ if (eif_header.eif_crc32 != crc) {
+ error_setg(errp, "CRC mismatch. Expected %u but header has %u.",
+ crc, eif_header.eif_crc32);
+ goto cleanup;
+ }
+
+ /*
+ * Let's append the initrd file from "-initrd" option if any. Although
+ * we pass the crc pointer to read_eif_ramdisk, it is not useful anymore.
+ * We have already done the crc mismatch check above this code.
+ */
+ if (machine_initrd) {
+ machine_initrd_f = fopen(machine_initrd, "rb");
+ if (machine_initrd_f == NULL) {
+ error_setg_errno(errp, errno, "Failed to open initrd file %s",
+ machine_initrd);
+ goto cleanup;
+ }
+
+ machine_initrd_size = get_file_size(machine_initrd_f, errp);
+ if (machine_initrd_size == -1) {
+ goto cleanup;
+ }
+
+ if (!read_eif_ramdisk(machine_initrd_f, initrd_path_f,
+ machine_initrd_size, hash0, hash2, &crc, errp)) {
+ goto cleanup;
+ }
+ }
+
+ if (!get_SHA384_hash(hash0, image_hash, errp)) {
+ goto cleanup;
+ }
+ if (!get_SHA384_hash(hash1, bootstrap_hash, errp)) {
+ goto cleanup;
+ }
+ if (!get_SHA384_hash(hash2, app_hash, errp)) {
+ goto cleanup;
+ }
+
+ fclose(f);
+ fclose(initrd_path_f);
+ safe_fclose(machine_initrd_f);
+ return true;
+
+ cleanup:
+ safe_fclose(f);
+ safe_fclose(initrd_path_f);
+ safe_fclose(machine_initrd_f);
+
+ safe_unlink(*kernel_path);
+ g_free(*kernel_path);
+ *kernel_path = NULL;
+
+ safe_unlink(*initrd_path);
+ g_free(*initrd_path);
+ *initrd_path = NULL;
+
+ g_free(*cmdline);
+ *cmdline = NULL;
+
+ return false;
+}
diff --git a/hw/core/eif.h b/hw/core/eif.h
new file mode 100644
index 0000000..fed3cb5
--- /dev/null
+++ b/hw/core/eif.h
@@ -0,0 +1,22 @@
+/*
+ * EIF (Enclave Image Format) related helpers
+ *
+ * Copyright (c) 2024 Dorjoy Chowdhury <dorjoychy111@gmail.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version. See the COPYING file in the
+ * top-level directory.
+ */
+
+#ifndef HW_CORE_EIF_H
+#define HW_CORE_EIF_H
+
+bool read_eif_file(const char *eif_path, const char *machine_initrd,
+ char **kernel_path, char **initrd_path,
+ char **kernel_cmdline, uint8_t *image_sha384,
+ uint8_t *bootstrap_sha384, uint8_t *app_sha384,
+ uint8_t *fingerprint_sha384, bool *signature_found,
+ Error **errp);
+
+#endif
+
diff --git a/hw/core/generic-loader.c b/hw/core/generic-loader.c
index ea8628b..e72bbde 100644
--- a/hw/core/generic-loader.c
+++ b/hw/core/generic-loader.c
@@ -31,9 +31,8 @@
*/
#include "qemu/osdep.h"
-#include "exec/tswap.h"
-#include "sysemu/dma.h"
-#include "sysemu/reset.h"
+#include "system/dma.h"
+#include "system/reset.h"
#include "hw/boards.h"
#include "hw/loader.h"
#include "hw/qdev-properties.h"
@@ -48,11 +47,8 @@ static void generic_loader_reset(void *opaque)
GenericLoaderState *s = GENERIC_LOADER(opaque);
if (s->set_pc) {
- CPUClass *cc = CPU_GET_CLASS(s->cpu);
cpu_reset(s->cpu);
- if (cc) {
- cc->set_pc(s->cpu, s->addr);
- }
+ cpu_set_pc(s->cpu, s->addr);
}
if (s->data_len) {
@@ -66,7 +62,6 @@ static void generic_loader_realize(DeviceState *dev, Error **errp)
{
GenericLoaderState *s = GENERIC_LOADER(dev);
hwaddr entry;
- int big_endian;
ssize_t size = 0;
s->set_pc = false;
@@ -134,14 +129,12 @@ static void generic_loader_realize(DeviceState *dev, Error **errp)
s->cpu = first_cpu;
}
- big_endian = target_words_bigendian();
-
if (s->file) {
AddressSpace *as = s->cpu ? s->cpu->as : NULL;
if (!s->force_raw) {
size = load_elf_as(s->file, NULL, NULL, NULL, &entry, NULL, NULL,
- NULL, big_endian, 0, 0, 0, as);
+ NULL, ELFDATANONE, 0, 0, 0, as);
if (size < 0) {
size = load_uimage_as(s->file, &entry, NULL, NULL, NULL, NULL,
@@ -179,7 +172,7 @@ static void generic_loader_unrealize(DeviceState *dev)
qemu_unregister_reset(generic_loader_reset, dev);
}
-static Property generic_loader_props[] = {
+static const Property generic_loader_props[] = {
DEFINE_PROP_UINT64("addr", GenericLoaderState, addr, 0),
DEFINE_PROP_UINT64("data", GenericLoaderState, data, 0),
DEFINE_PROP_UINT8("data-len", GenericLoaderState, data_len, 0),
@@ -187,10 +180,9 @@ static Property generic_loader_props[] = {
DEFINE_PROP_UINT32("cpu-num", GenericLoaderState, cpu_num, CPU_NONE),
DEFINE_PROP_BOOL("force-raw", GenericLoaderState, force_raw, false),
DEFINE_PROP_STRING("file", GenericLoaderState, file),
- DEFINE_PROP_END_OF_LIST(),
};
-static void generic_loader_class_init(ObjectClass *klass, void *data)
+static void generic_loader_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/core/gpio.c b/hw/core/gpio.c
index 80d07a6..6e32a8e 100644
--- a/hw/core/gpio.c
+++ b/hw/core/gpio.c
@@ -121,8 +121,7 @@ void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n,
name ? name : "unnamed-gpio-out", n);
if (input_pin && !OBJECT(input_pin)->parent) {
/* We need a name for object_property_set_link to work */
- object_property_add_child(container_get(qdev_get_machine(),
- "/unattached"),
+ object_property_add_child(machine_get_container("unattached"),
"non-qdev-gpio[*]", OBJECT(input_pin));
}
object_property_set_link(OBJECT(dev), propname,
diff --git a/hw/core/guest-loader.c b/hw/core/guest-loader.c
index 391c875..3db89d7 100644
--- a/hw/core/guest-loader.c
+++ b/hw/core/guest-loader.c
@@ -26,13 +26,13 @@
#include "qemu/osdep.h"
#include "hw/core/cpu.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "hw/loader.h"
#include "hw/qdev-properties.h"
#include "qapi/error.h"
#include "qemu/module.h"
#include "guest-loader.h"
-#include "sysemu/device_tree.h"
+#include "system/device_tree.h"
#include "hw/boards.h"
/*
@@ -111,15 +111,14 @@ static void guest_loader_realize(DeviceState *dev, Error **errp)
loader_insert_platform_data(s, size, errp);
}
-static Property guest_loader_props[] = {
+static const Property guest_loader_props[] = {
DEFINE_PROP_UINT64("addr", GuestLoaderState, addr, 0),
DEFINE_PROP_STRING("kernel", GuestLoaderState, kernel),
DEFINE_PROP_STRING("bootargs", GuestLoaderState, args),
DEFINE_PROP_STRING("initrd", GuestLoaderState, initrd),
- DEFINE_PROP_END_OF_LIST(),
};
-static void guest_loader_class_init(ObjectClass *klass, void *data)
+static void guest_loader_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/core/irq.c b/hw/core/irq.c
index 3f14e2d..6dd8d47 100644
--- a/hw/core/irq.c
+++ b/hw/core/irq.c
@@ -26,16 +26,6 @@
#include "hw/irq.h"
#include "qom/object.h"
-OBJECT_DECLARE_SIMPLE_TYPE(IRQState, IRQ)
-
-struct IRQState {
- Object parent_obj;
-
- qemu_irq_handler handler;
- void *opaque;
- int n;
-};
-
void qemu_set_irq(qemu_irq irq, int level)
{
if (!irq)
@@ -44,6 +34,29 @@ void qemu_set_irq(qemu_irq irq, int level)
irq->handler(irq->opaque, irq->n, level);
}
+static void init_irq_fields(IRQState *irq, qemu_irq_handler handler,
+ void *opaque, int n)
+{
+ irq->handler = handler;
+ irq->opaque = opaque;
+ irq->n = n;
+}
+
+void qemu_init_irq(IRQState *irq, qemu_irq_handler handler, void *opaque,
+ int n)
+{
+ object_initialize(irq, sizeof(*irq), TYPE_IRQ);
+ init_irq_fields(irq, handler, opaque, n);
+}
+
+void qemu_init_irqs(IRQState irq[], size_t count,
+ qemu_irq_handler handler, void *opaque)
+{
+ for (size_t i = 0; i < count; i++) {
+ qemu_init_irq(&irq[i], handler, opaque, i);
+ }
+}
+
qemu_irq *qemu_extend_irqs(qemu_irq *old, int n_old, qemu_irq_handler handler,
void *opaque, int n)
{
@@ -67,13 +80,8 @@ qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n)
qemu_irq qemu_allocate_irq(qemu_irq_handler handler, void *opaque, int n)
{
- IRQState *irq;
-
- irq = IRQ(object_new(TYPE_IRQ));
- irq->handler = handler;
- irq->opaque = opaque;
- irq->n = n;
-
+ IRQState *irq = IRQ(object_new(TYPE_IRQ));
+ init_irq_fields(irq, handler, opaque, n);
return irq;
}
diff --git a/hw/core/loader-fit.c b/hw/core/loader-fit.c
index 7ccc9d5..2dea485 100644
--- a/hw/core/loader-fit.c
+++ b/hw/core/loader-fit.c
@@ -20,20 +20,20 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu/units.h"
-#include "exec/memory.h"
+#include "system/memory.h"
#include "hw/loader.h"
#include "hw/loader-fit.h"
#include "qemu/cutils.h"
#include "qemu/error-report.h"
-#include "sysemu/device_tree.h"
+#include "system/device_tree.h"
#include <libfdt.h>
#include <zlib.h>
#define FIT_LOADER_MAX_PATH (128)
-static const void *fit_load_image_alloc(const void *itb, const char *name,
- int *poff, size_t *psz, Error **errp)
+static void *fit_load_image_alloc(const void *itb, const char *name,
+ int *poff, size_t *psz, Error **errp)
{
const void *data;
const char *comp;
@@ -80,11 +80,11 @@ static const void *fit_load_image_alloc(const void *itb, const char *name,
return NULL;
}
- data = g_realloc(uncomp_data, uncomp_len);
+ uncomp_data = g_realloc(uncomp_data, uncomp_len);
if (psz) {
*psz = uncomp_len;
}
- return data;
+ return uncomp_data;
}
error_setg(errp, "unknown compression '%s'", comp);
@@ -177,13 +177,12 @@ out:
static int fit_load_fdt(const struct fit_loader *ldr, const void *itb,
int cfg, void *opaque, const void *match_data,
- hwaddr kernel_end, Error **errp)
+ hwaddr kernel_end, void **pfdt, Error **errp)
{
ERRP_GUARD();
Error *err = NULL;
const char *name;
- const void *data;
- const void *load_data;
+ void *data;
hwaddr load_addr;
int img_off;
size_t sz;
@@ -194,7 +193,7 @@ static int fit_load_fdt(const struct fit_loader *ldr, const void *itb,
return 0;
}
- load_data = data = fit_load_image_alloc(itb, name, &img_off, &sz, errp);
+ data = fit_load_image_alloc(itb, name, &img_off, &sz, errp);
if (!data) {
error_prepend(errp, "unable to load FDT image from FIT: ");
return -EINVAL;
@@ -211,19 +210,23 @@ static int fit_load_fdt(const struct fit_loader *ldr, const void *itb,
}
if (ldr->fdt_filter) {
- load_data = ldr->fdt_filter(opaque, data, match_data, &load_addr);
+ void *filtered_data;
+
+ filtered_data = ldr->fdt_filter(opaque, data, match_data, &load_addr);
+ if (filtered_data != data) {
+ g_free(data);
+ data = filtered_data;
+ }
}
load_addr = ldr->addr_to_phys(opaque, load_addr);
- sz = fdt_totalsize(load_data);
- rom_add_blob_fixed(name, load_data, sz, load_addr);
+ sz = fdt_totalsize(data);
+ rom_add_blob_fixed(name, data, sz, load_addr);
- ret = 0;
+ *pfdt = data;
+ return 0;
out:
g_free((void *) data);
- if (data != load_data) {
- g_free((void *) load_data);
- }
return ret;
}
@@ -259,7 +262,8 @@ out:
return ret;
}
-int load_fit(const struct fit_loader *ldr, const char *filename, void *opaque)
+int load_fit(const struct fit_loader *ldr, const char *filename,
+ void **pfdt, void *opaque)
{
Error *err = NULL;
const struct fit_loader_match *match;
@@ -323,7 +327,7 @@ int load_fit(const struct fit_loader *ldr, const char *filename, void *opaque)
goto out;
}
- ret = fit_load_fdt(ldr, itb, cfg_off, opaque, match_data, kernel_end,
+ ret = fit_load_fdt(ldr, itb, cfg_off, opaque, match_data, kernel_end, pfdt,
&err);
if (ret) {
error_report_err(err);
diff --git a/hw/core/loader.c b/hw/core/loader.c
index 31593a1..e7056ba 100644
--- a/hw/core/loader.c
+++ b/hw/core/loader.c
@@ -51,17 +51,18 @@
#include "trace.h"
#include "hw/hw.h"
#include "disas/disas.h"
+#include "migration/cpr.h"
#include "migration/vmstate.h"
#include "monitor/monitor.h"
-#include "sysemu/reset.h"
-#include "sysemu/sysemu.h"
+#include "system/reset.h"
+#include "system/system.h"
#include "uboot_image.h"
#include "hw/loader.h"
#include "hw/nvram/fw_cfg.h"
-#include "exec/memory.h"
+#include "system/memory.h"
#include "hw/boards.h"
#include "qemu/cutils.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
#include "tcg/debuginfo.h"
#include <zlib.h>
@@ -144,7 +145,7 @@ ssize_t load_image_mr(const char *filename, MemoryRegion *mr)
{
ssize_t size;
- if (!memory_access_is_direct(mr, false)) {
+ if (!memory_access_is_direct(mr, false, MEMTXATTRS_UNSPECIFIED)) {
/* Can only load an image into RAM or ROM */
return -1;
}
@@ -225,7 +226,7 @@ static void bswap_ahdr(struct exec *e)
ssize_t load_aout(const char *filename, hwaddr addr, int max_sz,
- int bswap_needed, hwaddr target_page_size)
+ bool big_endian, hwaddr target_page_size)
{
int fd;
ssize_t size, ret;
@@ -240,7 +241,7 @@ ssize_t load_aout(const char *filename, hwaddr addr, int max_sz,
if (size < 0)
goto fail;
- if (bswap_needed) {
+ if (big_endian != HOST_BIG_ENDIAN) {
bswap_ahdr(&e);
}
@@ -409,11 +410,11 @@ ssize_t load_elf(const char *filename,
uint64_t (*elf_note_fn)(void *, void *, bool),
uint64_t (*translate_fn)(void *, uint64_t),
void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr,
- uint64_t *highaddr, uint32_t *pflags, int big_endian,
+ uint64_t *highaddr, uint32_t *pflags, int elf_data_order,
int elf_machine, int clear_lsb, int data_swab)
{
return load_elf_as(filename, elf_note_fn, translate_fn, translate_opaque,
- pentry, lowaddr, highaddr, pflags, big_endian,
+ pentry, lowaddr, highaddr, pflags, elf_data_order,
elf_machine, clear_lsb, data_swab, NULL);
}
@@ -422,29 +423,15 @@ ssize_t load_elf_as(const char *filename,
uint64_t (*elf_note_fn)(void *, void *, bool),
uint64_t (*translate_fn)(void *, uint64_t),
void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr,
- uint64_t *highaddr, uint32_t *pflags, int big_endian,
+ uint64_t *highaddr, uint32_t *pflags, int elf_data_order,
int elf_machine, int clear_lsb, int data_swab,
AddressSpace *as)
{
- return load_elf_ram(filename, elf_note_fn, translate_fn, translate_opaque,
- pentry, lowaddr, highaddr, pflags, big_endian,
- elf_machine, clear_lsb, data_swab, as, true);
-}
-
-/* return < 0 if error, otherwise the number of bytes loaded in memory */
-ssize_t load_elf_ram(const char *filename,
- uint64_t (*elf_note_fn)(void *, void *, bool),
- uint64_t (*translate_fn)(void *, uint64_t),
- void *translate_opaque, uint64_t *pentry,
- uint64_t *lowaddr, uint64_t *highaddr, uint32_t *pflags,
- int big_endian, int elf_machine, int clear_lsb,
- int data_swab, AddressSpace *as, bool load_rom)
-{
return load_elf_ram_sym(filename, elf_note_fn,
translate_fn, translate_opaque,
- pentry, lowaddr, highaddr, pflags, big_endian,
+ pentry, lowaddr, highaddr, pflags, elf_data_order,
elf_machine, clear_lsb, data_swab, as,
- load_rom, NULL);
+ true, NULL);
}
/* return < 0 if error, otherwise the number of bytes loaded in memory */
@@ -453,11 +440,12 @@ ssize_t load_elf_ram_sym(const char *filename,
uint64_t (*translate_fn)(void *, uint64_t),
void *translate_opaque, uint64_t *pentry,
uint64_t *lowaddr, uint64_t *highaddr,
- uint32_t *pflags, int big_endian, int elf_machine,
+ uint32_t *pflags, int elf_data_order, int elf_machine,
int clear_lsb, int data_swab,
AddressSpace *as, bool load_rom, symbol_fn_t sym_cb)
{
- int fd, data_order, target_data_order, must_swab;
+ const int host_data_order = HOST_BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB;
+ int fd, must_swab;
ssize_t ret = ELF_LOAD_FAILED;
uint8_t e_ident[EI_NIDENT];
@@ -475,23 +463,14 @@ ssize_t load_elf_ram_sym(const char *filename,
ret = ELF_LOAD_NOT_ELF;
goto fail;
}
-#if HOST_BIG_ENDIAN
- data_order = ELFDATA2MSB;
-#else
- data_order = ELFDATA2LSB;
-#endif
- must_swab = data_order != e_ident[EI_DATA];
- if (big_endian) {
- target_data_order = ELFDATA2MSB;
- } else {
- target_data_order = ELFDATA2LSB;
- }
- if (target_data_order != e_ident[EI_DATA]) {
+ if (elf_data_order != ELFDATANONE && elf_data_order != e_ident[EI_DATA]) {
ret = ELF_LOAD_WRONG_ENDIAN;
goto fail;
}
+ must_swab = host_data_order != e_ident[EI_DATA];
+
lseek(fd, 0, SEEK_SET);
if (e_ident[EI_CLASS] == ELFCLASS64) {
ret = load_elf64(filename, fd, elf_note_fn,
@@ -886,11 +865,11 @@ struct linux_efi_zboot_header {
*
* If the image is not a Linux EFI zboot image, do nothing and return success.
*/
-ssize_t unpack_efi_zboot_image(uint8_t **buffer, int *size)
+ssize_t unpack_efi_zboot_image(uint8_t **buffer, ssize_t *size)
{
const struct linux_efi_zboot_header *header;
uint8_t *data = NULL;
- int ploff, plsize;
+ ssize_t ploff, plsize;
ssize_t bytes;
/* ignore if this is too small to be a EFI zboot image */
@@ -1051,7 +1030,9 @@ static void *rom_set_mr(Rom *rom, Object *owner, const char *name, bool ro)
vmstate_register_ram_global(rom->mr);
data = memory_region_get_ram_ptr(rom->mr);
- memcpy(data, rom->data, rom->datasize);
+ if (!cpr_is_incoming()) {
+ memcpy(data, rom->data, rom->datasize);
+ }
return data;
}
@@ -1352,20 +1333,6 @@ void rom_set_fw(FWCfgState *f)
fw_cfg = f;
}
-void rom_set_order_override(int order)
-{
- if (!fw_cfg)
- return;
- fw_cfg_set_order_override(fw_cfg, order);
-}
-
-void rom_reset_order_override(void)
-{
- if (!fw_cfg)
- return;
- fw_cfg_reset_order_override(fw_cfg);
-}
-
void rom_transaction_begin(void)
{
Rom *rom;
@@ -1429,7 +1396,7 @@ typedef struct RomSec {
* work, but this way saves a little work later by avoiding
* dealing with "gaps" of 0 length.
*/
-static gint sort_secs(gconstpointer a, gconstpointer b)
+static gint sort_secs(gconstpointer a, gconstpointer b, gpointer d)
{
RomSec *ra = (RomSec *) a;
RomSec *rb = (RomSec *) b;
@@ -1482,7 +1449,7 @@ RomGap rom_find_largest_gap_between(hwaddr base, size_t size)
/* sentinel */
secs = add_romsec_to_list(secs, base + size, 1);
- secs = g_list_sort(secs, sort_secs);
+ secs = g_list_sort_with_data(secs, sort_secs, NULL);
for (it = g_list_first(secs); it; it = g_list_next(it)) {
cand = (RomSec *) it->data;
diff --git a/hw/core/machine-hmp-cmds.c b/hw/core/machine-hmp-cmds.c
index 8701f00..c6325cd 100644
--- a/hw/core/machine-hmp-cmds.c
+++ b/hw/core/machine-hmp-cmds.c
@@ -19,10 +19,10 @@
#include "qapi/error.h"
#include "qapi/qapi-builtin-visit.h"
#include "qapi/qapi-commands-machine.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "qapi/string-output-visitor.h"
#include "qemu/error-report.h"
-#include "sysemu/numa.h"
+#include "system/numa.h"
#include "hw/boards.h"
void hmp_info_cpus(Monitor *mon, const QDict *qdict)
diff --git a/hw/core/machine-qmp-cmds.c b/hw/core/machine-qmp-cmds.c
index 130217d..d82043e 100644
--- a/hw/core/machine-qmp-cmds.c
+++ b/hw/core/machine-qmp-cmds.c
@@ -15,16 +15,18 @@
#include "qapi/error.h"
#include "qapi/qapi-builtin-visit.h"
#include "qapi/qapi-commands-machine.h"
-#include "qapi/qmp/qobject.h"
+#include "qobject/qobject.h"
#include "qapi/qobject-input-visitor.h"
#include "qapi/type-helpers.h"
#include "qemu/uuid.h"
+#include "qemu/target-info.h"
#include "qom/qom-qobject.h"
-#include "sysemu/hostmem.h"
-#include "sysemu/hw_accel.h"
-#include "sysemu/numa.h"
-#include "sysemu/runstate.h"
-#include "sysemu/sysemu.h"
+#include "system/hostmem.h"
+#include "system/hw_accel.h"
+#include "system/numa.h"
+#include "system/runstate.h"
+#include "system/system.h"
+#include "hw/s390x/storage-keys.h"
/*
* fast means: we NEVER interrupt vCPU threads to retrieve
@@ -72,6 +74,7 @@ MachineInfoList *qmp_query_machines(bool has_compat_props, bool compat_props,
for (el = machines; el; el = el->next) {
MachineClass *mc = el->data;
+ const char *default_cpu_type = machine_class_default_cpu_type(mc);
MachineInfo *info;
info = g_malloc0(sizeof(*info));
@@ -90,8 +93,8 @@ MachineInfoList *qmp_query_machines(bool has_compat_props, bool compat_props,
info->numa_mem_supported = mc->numa_mem_supported;
info->deprecated = !!mc->deprecation_reason;
info->acpi = !!object_class_property_find(OBJECT_CLASS(mc), "acpi");
- if (mc->default_cpu_type) {
- info->default_cpu_type = g_strdup(mc->default_cpu_type);
+ if (default_cpu_type) {
+ info->default_cpu_type = g_strdup(default_cpu_type);
}
if (mc->default_ram_id) {
info->default_ram_id = g_strdup(mc->default_ram_id);
@@ -132,9 +135,9 @@ CurrentMachineParams *qmp_query_current_machine(Error **errp)
return params;
}
-TargetInfo *qmp_query_target(Error **errp)
+QemuTargetInfo *qmp_query_target(Error **errp)
{
- TargetInfo *info = g_malloc0(sizeof(*info));
+ QemuTargetInfo *info = g_malloc0(sizeof(*info));
info->arch = qapi_enum_parse(&SysEmuTarget_lookup, target_name(), -1,
&error_abort);
@@ -406,3 +409,16 @@ GuidInfo *qmp_query_vm_generation_id(Error **errp)
info->guid = qemu_uuid_unparse_strdup(&vms->guid);
return info;
}
+
+void qmp_dump_skeys(const char *filename, Error **errp)
+{
+ ObjectClass *mc = object_get_class(qdev_get_machine());
+ ObjectClass *oc = object_class_dynamic_cast(mc, TYPE_DUMP_SKEYS_INTERFACE);
+
+ if (!oc) {
+ error_setg(errp, "Storage keys information not available"
+ " for this architecture");
+ return;
+ }
+ DUMP_SKEYS_INTERFACE_CLASS(oc)->qmp_dump_skeys(filename, errp);
+}
diff --git a/hw/core/machine-smp.c b/hw/core/machine-smp.c
index 5d8d7ed..0be0ac0 100644
--- a/hw/core/machine-smp.c
+++ b/hw/core/machine-smp.c
@@ -261,6 +261,82 @@ void machine_parse_smp_config(MachineState *ms,
}
}
+static bool machine_check_topo_support(MachineState *ms,
+ CpuTopologyLevel topo,
+ Error **errp)
+{
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+
+ if ((topo == CPU_TOPOLOGY_LEVEL_MODULE && !mc->smp_props.modules_supported) ||
+ (topo == CPU_TOPOLOGY_LEVEL_CLUSTER && !mc->smp_props.clusters_supported) ||
+ (topo == CPU_TOPOLOGY_LEVEL_DIE && !mc->smp_props.dies_supported) ||
+ (topo == CPU_TOPOLOGY_LEVEL_BOOK && !mc->smp_props.books_supported) ||
+ (topo == CPU_TOPOLOGY_LEVEL_DRAWER && !mc->smp_props.drawers_supported)) {
+ error_setg(errp,
+ "Invalid topology level: %s. "
+ "The topology level is not supported by this machine",
+ CpuTopologyLevel_str(topo));
+ return false;
+ }
+
+ return true;
+}
+
+bool machine_parse_smp_cache(MachineState *ms,
+ const SmpCachePropertiesList *caches,
+ Error **errp)
+{
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+ const SmpCachePropertiesList *node;
+ DECLARE_BITMAP(caches_bitmap, CACHE_LEVEL_AND_TYPE__MAX);
+
+ bitmap_zero(caches_bitmap, CACHE_LEVEL_AND_TYPE__MAX);
+ for (node = caches; node; node = node->next) {
+ /* Prohibit users from repeating settings. */
+ if (test_bit(node->value->cache, caches_bitmap)) {
+ error_setg(errp,
+ "Invalid cache properties: %s. "
+ "The cache properties are duplicated",
+ CacheLevelAndType_str(node->value->cache));
+ return false;
+ }
+
+ machine_set_cache_topo_level(ms, node->value->cache,
+ node->value->topology);
+ set_bit(node->value->cache, caches_bitmap);
+ }
+
+ for (int i = 0; i < CACHE_LEVEL_AND_TYPE__MAX; i++) {
+ const SmpCacheProperties *props = &ms->smp_cache.props[i];
+
+ /*
+ * Reject non "default" topology level if the cache isn't
+ * supported by the machine.
+ */
+ if (props->topology != CPU_TOPOLOGY_LEVEL_DEFAULT &&
+ !mc->smp_props.cache_supported[props->cache]) {
+ error_setg(errp,
+ "%s cache topology not supported by this machine",
+ CacheLevelAndType_str(props->cache));
+ return false;
+ }
+
+ if (props->topology == CPU_TOPOLOGY_LEVEL_THREAD) {
+ error_setg(errp,
+ "%s level cache not supported by this machine",
+ CpuTopologyLevel_str(props->topology));
+ return false;
+ }
+
+ if (!machine_check_topo_support(ms, props->topology, errp)) {
+ return false;
+ }
+ }
+
+ mc->smp_props.has_caches = true;
+ return true;
+}
+
unsigned int machine_topo_get_cores_per_socket(const MachineState *ms)
{
return ms->smp.cores * ms->smp.modules * ms->smp.clusters * ms->smp.dies;
@@ -270,3 +346,63 @@ unsigned int machine_topo_get_threads_per_socket(const MachineState *ms)
{
return ms->smp.threads * machine_topo_get_cores_per_socket(ms);
}
+
+CpuTopologyLevel machine_get_cache_topo_level(const MachineState *ms,
+ CacheLevelAndType cache)
+{
+ return ms->smp_cache.props[cache].topology;
+}
+
+void machine_set_cache_topo_level(MachineState *ms, CacheLevelAndType cache,
+ CpuTopologyLevel level)
+{
+ ms->smp_cache.props[cache].topology = level;
+}
+
+/*
+ * When both cache1 and cache2 are configured with specific topology levels
+ * (not default level), is cache1's topology level higher than cache2?
+ */
+static bool smp_cache_topo_cmp(const SmpCache *smp_cache,
+ CacheLevelAndType cache1,
+ CacheLevelAndType cache2)
+{
+ /*
+ * Before comparing, the "default" topology level should be replaced
+ * with the specific level.
+ */
+ assert(smp_cache->props[cache1].topology != CPU_TOPOLOGY_LEVEL_DEFAULT);
+
+ return smp_cache->props[cache1].topology > smp_cache->props[cache2].topology;
+}
+
+/*
+ * Currently, we have no way to expose the arch-specific default cache model
+ * because the cache model is sometimes related to the CPU model (e.g., i386).
+ *
+ * We can only check the correctness of the cache topology after the arch loads
+ * the user-configured cache model from MachineState and consumes the special
+ * "default" level by replacing it with the specific level.
+ */
+bool machine_check_smp_cache(const MachineState *ms, Error **errp)
+{
+ if (smp_cache_topo_cmp(&ms->smp_cache, CACHE_LEVEL_AND_TYPE_L1D,
+ CACHE_LEVEL_AND_TYPE_L2) ||
+ smp_cache_topo_cmp(&ms->smp_cache, CACHE_LEVEL_AND_TYPE_L1I,
+ CACHE_LEVEL_AND_TYPE_L2)) {
+ error_setg(errp,
+ "Invalid smp cache topology. "
+ "L2 cache topology level shouldn't be lower than L1 cache");
+ return false;
+ }
+
+ if (smp_cache_topo_cmp(&ms->smp_cache, CACHE_LEVEL_AND_TYPE_L2,
+ CACHE_LEVEL_AND_TYPE_L3)) {
+ error_setg(errp,
+ "Invalid smp cache topology. "
+ "L3 cache topology level shouldn't be lower than L2 cache");
+ return false;
+ }
+
+ return true;
+}
diff --git a/hw/core/machine.c b/hw/core/machine.c
index bc38cad..e869821 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -11,35 +11,61 @@
*/
#include "qemu/osdep.h"
+#include "qemu/units.h"
#include "qemu/accel.h"
-#include "sysemu/replay.h"
+#include "system/replay.h"
#include "hw/boards.h"
#include "hw/loader.h"
+#include "qemu/error-report.h"
#include "qapi/error.h"
#include "qapi/qapi-visit-machine.h"
+#include "qapi/qapi-commands-machine.h"
#include "qemu/madvise.h"
#include "qom/object_interfaces.h"
-#include "sysemu/cpus.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
-#include "sysemu/xen.h"
-#include "sysemu/qtest.h"
+#include "system/cpus.h"
+#include "system/system.h"
+#include "system/reset.h"
+#include "system/runstate.h"
+#include "system/xen.h"
+#include "system/qtest.h"
#include "hw/pci/pci_bridge.h"
#include "hw/mem/nvdimm.h"
#include "migration/global_state.h"
-#include "exec/confidential-guest-support.h"
+#include "system/confidential-guest-support.h"
#include "hw/virtio/virtio-pci.h"
#include "hw/virtio/virtio-net.h"
#include "hw/virtio/virtio-iommu.h"
#include "audio/audio.h"
+GlobalProperty hw_compat_10_0[] = {
+ { "scsi-hd", "dpofua", "off" },
+};
+const size_t hw_compat_10_0_len = G_N_ELEMENTS(hw_compat_10_0);
+
+GlobalProperty hw_compat_9_2[] = {
+ { "arm-cpu", "backcompat-pauth-default-use-qarma5", "true"},
+ { "virtio-balloon-pci", "vectors", "0" },
+ { "virtio-balloon-pci-transitional", "vectors", "0" },
+ { "virtio-balloon-pci-non-transitional", "vectors", "0" },
+ { "virtio-mem-pci", "vectors", "0" },
+ { "migration", "multifd-clean-tls-termination", "false" },
+ { "migration", "send-switchover-start", "off"},
+ { "vfio-pci", "x-migration-multifd-transfer", "off" },
+};
+const size_t hw_compat_9_2_len = G_N_ELEMENTS(hw_compat_9_2);
+
+GlobalProperty hw_compat_9_1[] = {
+ { TYPE_PCI_DEVICE, "x-pcie-ext-tag", "false" },
+};
+const size_t hw_compat_9_1_len = G_N_ELEMENTS(hw_compat_9_1);
+
GlobalProperty hw_compat_9_0[] = {
- {"arm-cpu", "backcompat-cntfrq", "true" },
- {"scsi-disk-base", "migrate-emulated-scsi-request", "false" },
- {"vfio-pci", "skip-vsc-check", "false" },
+ { "arm-cpu", "backcompat-cntfrq", "true" },
+ { "scsi-hd", "migrate-emulated-scsi-request", "false" },
+ { "scsi-cd", "migrate-emulated-scsi-request", "false" },
+ { "vfio-pci", "skip-vsc-check", "false" },
{ "virtio-pci", "x-pcie-pm-no-soft-reset", "off" },
- {"sd-card", "spec_version", "2" },
+ { "sd-card", "spec_version", "2" },
};
const size_t hw_compat_9_0_len = G_N_ELEMENTS(hw_compat_9_0);
@@ -259,51 +285,6 @@ GlobalProperty hw_compat_2_6[] = {
};
const size_t hw_compat_2_6_len = G_N_ELEMENTS(hw_compat_2_6);
-GlobalProperty hw_compat_2_5[] = {
- { "isa-fdc", "fallback", "144" },
- { "pvscsi", "x-old-pci-configuration", "on" },
- { "pvscsi", "x-disable-pcie", "on" },
- { "vmxnet3", "x-old-msi-offsets", "on" },
- { "vmxnet3", "x-disable-pcie", "on" },
-};
-const size_t hw_compat_2_5_len = G_N_ELEMENTS(hw_compat_2_5);
-
-GlobalProperty hw_compat_2_4[] = {
- { "e1000", "extra_mac_registers", "off" },
- { "virtio-pci", "x-disable-pcie", "on" },
- { "virtio-pci", "migrate-extra", "off" },
- { "fw_cfg_mem", "dma_enabled", "off" },
- { "fw_cfg_io", "dma_enabled", "off" }
-};
-const size_t hw_compat_2_4_len = G_N_ELEMENTS(hw_compat_2_4);
-
-GlobalProperty hw_compat_2_3[] = {
- { "virtio-blk-pci", "any_layout", "off" },
- { "virtio-balloon-pci", "any_layout", "off" },
- { "virtio-serial-pci", "any_layout", "off" },
- { "virtio-9p-pci", "any_layout", "off" },
- { "virtio-rng-pci", "any_layout", "off" },
- { TYPE_PCI_DEVICE, "x-pcie-lnksta-dllla", "off" },
- { "migration", "send-configuration", "off" },
- { "migration", "send-section-footer", "off" },
- { "migration", "store-global-state", "off" },
-};
-const size_t hw_compat_2_3_len = G_N_ELEMENTS(hw_compat_2_3);
-
-GlobalProperty hw_compat_2_2[] = {};
-const size_t hw_compat_2_2_len = G_N_ELEMENTS(hw_compat_2_2);
-
-GlobalProperty hw_compat_2_1[] = {
- { "intel-hda", "old_msi_addr", "on" },
- { "VGA", "qemu-extended-regs", "off" },
- { "secondary-vga", "qemu-extended-regs", "off" },
- { "virtio-scsi-pci", "any_layout", "off" },
- { "usb-mouse", "usb_version", "1" },
- { "usb-kbd", "usb_version", "1" },
- { "virtio-pci", "virtio-pci-bus-master-bug-migration", "on" },
-};
-const size_t hw_compat_2_1_len = G_N_ELEMENTS(hw_compat_2_1);
-
MachineState *current_machine;
static char *machine_get_kernel(Object *obj, Error **errp)
@@ -321,6 +302,21 @@ static void machine_set_kernel(Object *obj, const char *value, Error **errp)
ms->kernel_filename = g_strdup(value);
}
+static char *machine_get_shim(Object *obj, Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+
+ return g_strdup(ms->shim_filename);
+}
+
+static void machine_set_shim(Object *obj, const char *value, Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+
+ g_free(ms->shim_filename);
+ ms->shim_filename = g_strdup(value);
+}
+
static char *machine_get_initrd(Object *obj, Error **errp)
{
MachineState *ms = MACHINE(obj);
@@ -456,6 +452,22 @@ static void machine_set_mem_merge(Object *obj, bool value, Error **errp)
ms->mem_merge = value;
}
+#ifdef CONFIG_POSIX
+static bool machine_get_aux_ram_share(Object *obj, Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+
+ return ms->aux_ram_share;
+}
+
+static void machine_set_aux_ram_share(Object *obj, bool value, Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+
+ ms->aux_ram_share = value;
+}
+#endif
+
static bool machine_get_usb(Object *obj, Error **errp)
{
MachineState *ms = MACHINE(obj);
@@ -617,11 +629,19 @@ static void machine_set_mem(Object *obj, Visitor *v, const char *name,
mem->size = mc->fixup_ram_size(mem->size);
}
if ((ram_addr_t)mem->size != mem->size) {
- error_setg(errp, "ram size too large");
+ error_setg(errp, "ram size %llu exceeds permitted maximum %llu",
+ (unsigned long long)mem->size,
+ (unsigned long long)RAM_ADDR_MAX);
goto out_free;
}
if (mem->has_max_size) {
+ if ((ram_addr_t)mem->max_size != mem->max_size) {
+ error_setg(errp, "ram size %llu exceeds permitted maximum %llu",
+ (unsigned long long)mem->max_size,
+ (unsigned long long)RAM_ADDR_MAX);
+ goto out_free;
+ }
if (mem->max_size < mem->size) {
error_setg(errp, "invalid value of maxmem: "
"maximum memory size (0x%" PRIx64 ") must be at least "
@@ -928,6 +948,40 @@ static void machine_set_smp(Object *obj, Visitor *v, const char *name,
machine_parse_smp_config(ms, config, errp);
}
+static void machine_get_smp_cache(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+ SmpCache *cache = &ms->smp_cache;
+ SmpCachePropertiesList *head = NULL;
+ SmpCachePropertiesList **tail = &head;
+
+ for (int i = 0; i < CACHE_LEVEL_AND_TYPE__MAX; i++) {
+ SmpCacheProperties *node = g_new(SmpCacheProperties, 1);
+
+ node->cache = cache->props[i].cache;
+ node->topology = cache->props[i].topology;
+ QAPI_LIST_APPEND(tail, node);
+ }
+
+ visit_type_SmpCachePropertiesList(v, name, &head, errp);
+ qapi_free_SmpCachePropertiesList(head);
+}
+
+static void machine_set_smp_cache(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+ SmpCachePropertiesList *caches;
+
+ if (!visit_type_SmpCachePropertiesList(v, name, &caches, errp)) {
+ return;
+ }
+
+ machine_parse_smp_cache(ms, caches, errp);
+ qapi_free_SmpCachePropertiesList(caches);
+}
+
static void machine_get_boot(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
@@ -997,24 +1051,70 @@ void machine_add_audiodev_property(MachineClass *mc)
"Audiodev to use for default machine devices");
}
-static void machine_class_init(ObjectClass *oc, void *data)
+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;
+}
+
+static void machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
/* Default 128 MB as guest ram size */
mc->default_ram_size = 128 * MiB;
mc->rom_file_has_mr = true;
+ /*
+ * SMBIOS 3.1.0 7.18.5 Memory Device — Extended Size
+ * use max possible value that could be encoded into
+ * 'Extended Size' field (2047Tb).
+ */
+ mc->smbios_memory_device_size = 2047 * TiB;
/* numa node memory size aligned on 8MB by default.
* On Linux, each node's border has to be 8MB aligned
*/
mc->numa_mem_align_shift = 23;
+ mc->create_default_memdev = create_default_memdev;
+
object_class_property_add_str(oc, "kernel",
machine_get_kernel, machine_set_kernel);
object_class_property_set_description(oc, "kernel",
"Linux kernel image file");
+ object_class_property_add_str(oc, "shim",
+ machine_get_shim, machine_set_shim);
+ object_class_property_set_description(oc, "shim",
+ "shim.efi file");
+
object_class_property_add_str(oc, "initrd",
machine_get_initrd, machine_set_initrd);
object_class_property_set_description(oc, "initrd",
@@ -1047,6 +1147,11 @@ static void machine_class_init(ObjectClass *oc, void *data)
object_class_property_set_description(oc, "smp",
"CPU topology");
+ object_class_property_add(oc, "smp-cache", "SmpCachePropertiesWrapper",
+ machine_get_smp_cache, machine_set_smp_cache, NULL, NULL);
+ object_class_property_set_description(oc, "smp-cache",
+ "Cache properties list for SMP machine");
+
object_class_property_add(oc, "phandle-start", "int",
machine_get_phandle_start, machine_set_phandle_start,
NULL, NULL);
@@ -1068,6 +1173,12 @@ static void machine_class_init(ObjectClass *oc, void *data)
object_class_property_set_description(oc, "mem-merge",
"Enable/disable memory merge support");
+#ifdef CONFIG_POSIX
+ object_class_property_add_bool(oc, "aux-ram-share",
+ machine_get_aux_ram_share,
+ machine_set_aux_ram_share);
+#endif
+
object_class_property_add_bool(oc, "usb",
machine_get_usb, machine_set_usb);
object_class_property_set_description(oc, "usb",
@@ -1116,7 +1227,7 @@ static void machine_class_init(ObjectClass *oc, void *data)
"Memory size configuration");
}
-static void machine_class_base_init(ObjectClass *oc, void *data)
+static void machine_class_base_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
mc->max_cpus = mc->max_cpus ?: 1;
@@ -1137,9 +1248,6 @@ static void machine_initfn(Object *obj)
MachineState *ms = MACHINE(obj);
MachineClass *mc = MACHINE_GET_CLASS(obj);
- container_get(obj, "/peripheral");
- container_get(obj, "/peripheral-anon");
-
ms->dump_guest_core = true;
ms->mem_merge = (QEMU_MADV_MERGEABLE != QEMU_MADV_INVALID);
ms->enable_graphics = true;
@@ -1185,6 +1293,11 @@ static void machine_initfn(Object *obj)
ms->smp.cores = 1;
ms->smp.threads = 1;
+ for (int i = 0; i < CACHE_LEVEL_AND_TYPE__MAX; i++) {
+ ms->smp_cache.props[i].cache = (CacheLevelAndType)i;
+ ms->smp_cache.props[i].topology = CPU_TOPOLOGY_LEVEL_DEFAULT;
+ }
+
machine_copy_boot_config(ms, &(BootConfiguration){ 0 });
}
@@ -1403,38 +1516,6 @@ MemoryRegion *machine_consume_memdev(MachineState *machine,
return ret;
}
-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;
-}
-
const char *machine_class_default_cpu_type(MachineClass *mc)
{
if (mc->valid_cpu_types && !mc->valid_cpu_types[1]) {
@@ -1538,7 +1619,9 @@ void machine_run_board_init(MachineState *machine, const char *mem_path, Error *
machine_class->default_ram_id);
return;
}
- if (!create_default_memdev(current_machine, mem_path, errp)) {
+
+ if (!machine_class->create_default_memdev(current_machine, mem_path,
+ errp)) {
return;
}
}
@@ -1603,6 +1686,22 @@ void qemu_remove_machine_init_done_notifier(Notifier *notify)
notifier_remove(notify);
}
+static void handle_machine_dumpdtb(MachineState *ms)
+{
+ if (!ms->dumpdtb) {
+ return;
+ }
+#ifdef CONFIG_FDT
+ qmp_dumpdtb(ms->dumpdtb, &error_fatal);
+ exit(0);
+#else
+ error_report("This machine doesn't have an FDT");
+ error_printf("(this machine type definitely doesn't use FDT, and "
+ "this QEMU doesn't have FDT support compiled in)\n");
+ exit(1);
+#endif
+}
+
void qdev_machine_creation_done(void)
{
cpu_synchronize_all_post_init();
@@ -1632,6 +1731,12 @@ void qdev_machine_creation_done(void)
notifier_list_notify(&machine_init_done_notifiers, NULL);
+ /*
+ * If the user used -machine dumpdtb=file.dtb to request that we
+ * dump the DTB to a file, do it now, and exit.
+ */
+ handle_machine_dumpdtb(current_machine);
+
if (rom_check_and_register_reset() != 0) {
exit(1);
}
diff --git a/hw/core/meson.build b/hw/core/meson.build
index a3d9bab..b5a545a 100644
--- a/hw/core/meson.build
+++ b/hw/core/meson.build
@@ -24,9 +24,10 @@ system_ss.add(when: 'CONFIG_REGISTER', if_true: files('register.c'))
system_ss.add(when: 'CONFIG_SPLIT_IRQ', if_true: files('split-irq.c'))
system_ss.add(when: 'CONFIG_XILINX_AXI', if_true: files('stream.c'))
system_ss.add(when: 'CONFIG_PLATFORM_BUS', if_true: files('sysbus-fdt.c'))
+system_ss.add(when: 'CONFIG_EIF', if_true: [files('eif.c'), zlib, libcbor, gnutls])
system_ss.add(files(
- 'cpu-sysemu.c',
+ 'cpu-system.c',
'fw-path-provider.c',
'gpio.c',
'hotplug.c',
@@ -45,3 +46,7 @@ system_ss.add(files(
'vm-change-state-handler.c',
'clock-vmstate.c',
))
+user_ss.add(files(
+ 'cpu-user.c',
+ 'qdev-user.c',
+))
diff --git a/hw/core/null-machine.c b/hw/core/null-machine.c
index f586a4b..a6e477a 100644
--- a/hw/core/null-machine.c
+++ b/hw/core/null-machine.c
@@ -14,7 +14,7 @@
#include "qemu/osdep.h"
#include "qemu/error-report.h"
#include "hw/boards.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
#include "hw/core/cpu.h"
static void machine_none_init(MachineState *mch)
@@ -53,7 +53,6 @@ static void machine_none_machine_init(MachineClass *mc)
mc->no_parallel = 1;
mc->no_floppy = 1;
mc->no_cdrom = 1;
- mc->no_sdcard = 1;
}
DEFINE_MACHINE("none", machine_none_machine_init)
diff --git a/hw/core/numa.c b/hw/core/numa.c
index f8ce332..218576f 100644
--- a/hw/core/numa.c
+++ b/hw/core/numa.c
@@ -24,15 +24,15 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
-#include "sysemu/hostmem.h"
-#include "sysemu/numa.h"
+#include "system/hostmem.h"
+#include "system/numa.h"
#include "exec/cpu-common.h"
#include "exec/ramlist.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "qapi/opts-visitor.h"
#include "qapi/qapi-visit-machine.h"
-#include "sysemu/qtest.h"
+#include "system/qtest.h"
#include "hw/core/cpu.h"
#include "hw/mem/pc-dimm.h"
#include "hw/boards.h"
@@ -249,7 +249,7 @@ void parse_numa_hmat_lb(NumaState *numa_state, NumaHmatLBOptions *node,
lb_data.initiator = node->initiator;
lb_data.target = node->target;
- if (node->data_type <= HMATLB_DATA_TYPE_WRITE_LATENCY) {
+ if (node->data_type <= HMAT_LB_DATA_TYPE_WRITE_LATENCY) {
/* Input latency data */
if (!node->has_latency) {
@@ -313,7 +313,7 @@ void parse_numa_hmat_lb(NumaState *numa_state, NumaHmatLBOptions *node,
numa_info[node->target].lb_info_provided |= BIT(0);
}
lb_data.data = node->latency;
- } else if (node->data_type >= HMATLB_DATA_TYPE_ACCESS_BANDWIDTH) {
+ } else if (node->data_type >= HMAT_LB_DATA_TYPE_ACCESS_BANDWIDTH) {
/* Input bandwidth data */
if (!node->has_bandwidth) {
error_setg(errp, "Missing 'bandwidth' option");
@@ -380,7 +380,7 @@ void parse_numa_hmat_lb(NumaState *numa_state, NumaHmatLBOptions *node,
}
lb_data.data = node->bandwidth;
} else {
- assert(0);
+ g_assert_not_reached();
}
g_array_append_val(hmat_lb->list, lb_data);
diff --git a/hw/core/or-irq.c b/hw/core/or-irq.c
index 13907df..3942c70 100644
--- a/hw/core/or-irq.c
+++ b/hw/core/or-irq.c
@@ -115,16 +115,15 @@ static const VMStateDescription vmstate_or_irq = {
},
};
-static Property or_irq_properties[] = {
+static const Property or_irq_properties[] = {
DEFINE_PROP_UINT16("num-lines", OrIRQState, num_lines, 1),
- DEFINE_PROP_END_OF_LIST(),
};
-static void or_irq_class_init(ObjectClass *klass, void *data)
+static void or_irq_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = or_irq_reset;
+ device_class_set_legacy_reset(dc, or_irq_reset);
device_class_set_props(dc, or_irq_properties);
dc->realize = or_irq_realize;
dc->vmsd = &vmstate_or_irq;
diff --git a/hw/core/platform-bus.c b/hw/core/platform-bus.c
index b8487b2..6950063 100644
--- a/hw/core/platform-bus.c
+++ b/hw/core/platform-bus.c
@@ -145,9 +145,12 @@ static void platform_bus_map_mmio(PlatformBusDevice *pbus, SysBusDevice *sbdev,
* the target device's memory region
*/
for (off = 0; off < pbus->mmio_size; off += alignment) {
- if (!memory_region_find(&pbus->mmio, off, size).mr) {
+ MemoryRegion *mr = memory_region_find(&pbus->mmio, off, size).mr;
+ if (!mr) {
found_region = true;
break;
+ } else {
+ memory_region_unref(mr);
}
}
@@ -201,13 +204,12 @@ static void platform_bus_realize(DeviceState *dev, Error **errp)
plaform_bus_refresh_irqs(pbus);
}
-static Property platform_bus_properties[] = {
+static const Property platform_bus_properties[] = {
DEFINE_PROP_UINT32("num_irqs", PlatformBusDevice, num_irqs, 0),
DEFINE_PROP_UINT32("mmio_size", PlatformBusDevice, mmio_size, 0),
- DEFINE_PROP_END_OF_LIST()
};
-static void platform_bus_class_init(ObjectClass *klass, void *data)
+static void platform_bus_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c
index b151759..0aeb10f 100644
--- a/hw/core/ptimer.c
+++ b/hw/core/ptimer.c
@@ -11,8 +11,8 @@
#include "migration/vmstate.h"
#include "qemu/host-utils.h"
#include "exec/replay-core.h"
-#include "sysemu/cpu-timers.h"
-#include "sysemu/qtest.h"
+#include "exec/icount.h"
+#include "system/qtest.h"
#include "block/aio.h"
#include "hw/clock.h"
@@ -83,7 +83,7 @@ static void ptimer_reload(ptimer_state *s, int delta_adjust)
delta = s->delta = s->limit;
}
- if (s->period == 0) {
+ if (s->period == 0 && s->period_frac == 0) {
if (!qtest_enabled()) {
fprintf(stderr, "Timer with period zero, disabling\n");
}
@@ -309,7 +309,7 @@ void ptimer_run(ptimer_state *s, int oneshot)
assert(s->in_transaction);
- if (was_disabled && s->period == 0) {
+ if (was_disabled && s->period == 0 && s->period_frac == 0) {
if (!qtest_enabled()) {
fprintf(stderr, "Timer with period zero, disabling\n");
}
diff --git a/hw/core/qdev-clock.c b/hw/core/qdev-clock.c
index 8279957..dacafa4 100644
--- a/hw/core/qdev-clock.c
+++ b/hw/core/qdev-clock.c
@@ -22,7 +22,7 @@
* Add a new clock in a device
*/
static NamedClockList *qdev_init_clocklist(DeviceState *dev, const char *name,
- bool output, Clock *clk)
+ bool alias, bool output, Clock *clk)
{
NamedClockList *ncl;
@@ -38,39 +38,8 @@ static NamedClockList *qdev_init_clocklist(DeviceState *dev, const char *name,
*/
ncl = g_new0(NamedClockList, 1);
ncl->name = g_strdup(name);
+ ncl->alias = alias;
ncl->output = output;
- ncl->alias = (clk != NULL);
-
- /*
- * Trying to create a clock whose name clashes with some other
- * clock or property is a bug in the caller and we will abort().
- */
- if (clk == NULL) {
- clk = CLOCK(object_new(TYPE_CLOCK));
- object_property_add_child(OBJECT(dev), name, OBJECT(clk));
- if (output) {
- /*
- * Remove object_new()'s initial reference.
- * Note that for inputs, the reference created by object_new()
- * will be deleted in qdev_finalize_clocklist().
- */
- object_unref(OBJECT(clk));
- }
- } else {
- object_property_add_link(OBJECT(dev), name,
- object_get_typename(OBJECT(clk)),
- (Object **) &ncl->clock,
- NULL, OBJ_PROP_LINK_STRONG);
- /*
- * Since the link property has the OBJ_PROP_LINK_STRONG flag, the clk
- * object reference count gets decremented on property deletion.
- * However object_property_add_link does not increment it since it
- * doesn't know the linked object. Increment it here to ensure the
- * aliased clock stays alive during this device life-time.
- */
- object_ref(OBJECT(clk));
- }
-
ncl->clock = clk;
QLIST_INSERT_HEAD(&dev->clocks, ncl, node);
@@ -84,14 +53,11 @@ void qdev_finalize_clocklist(DeviceState *dev)
QLIST_FOREACH_SAFE(ncl, &dev->clocks, node, ncl_next) {
QLIST_REMOVE(ncl, node);
- if (!ncl->output && !ncl->alias) {
+ if (!ncl->alias) {
/*
* We kept a reference on the input clock to ensure it lives up to
- * this point so we can safely remove the callback.
- * It avoids having a callback to a deleted object if ncl->clock
- * is still referenced somewhere else (eg: by a clock output).
+ * this point; it is used by the monitor to show the frequency.
*/
- clock_clear_callback(ncl->clock);
object_unref(OBJECT(ncl->clock));
}
g_free(ncl->name);
@@ -101,29 +67,25 @@ void qdev_finalize_clocklist(DeviceState *dev)
Clock *qdev_init_clock_out(DeviceState *dev, const char *name)
{
- NamedClockList *ncl;
-
- assert(name);
-
- ncl = qdev_init_clocklist(dev, name, true, NULL);
+ Clock *clk = CLOCK(object_new(TYPE_CLOCK));
+ object_property_add_child(OBJECT(dev), name, OBJECT(clk));
- return ncl->clock;
+ qdev_init_clocklist(dev, name, false, true, clk);
+ return clk;
}
Clock *qdev_init_clock_in(DeviceState *dev, const char *name,
ClockCallback *callback, void *opaque,
unsigned int events)
{
- NamedClockList *ncl;
-
- assert(name);
-
- ncl = qdev_init_clocklist(dev, name, false, NULL);
+ Clock *clk = CLOCK(object_new(TYPE_CLOCK));
+ object_property_add_child(OBJECT(dev), name, OBJECT(clk));
+ qdev_init_clocklist(dev, name, false, false, clk);
if (callback) {
- clock_set_callback(ncl->clock, callback, opaque, events);
+ clock_set_callback(clk, callback, opaque, events);
}
- return ncl->clock;
+ return clk;
}
void qdev_init_clocks(DeviceState *dev, const ClockPortInitArray clocks)
@@ -194,15 +156,25 @@ Clock *qdev_get_clock_out(DeviceState *dev, const char *name)
Clock *qdev_alias_clock(DeviceState *dev, const char *name,
DeviceState *alias_dev, const char *alias_name)
{
- NamedClockList *ncl;
-
- assert(name && alias_name);
+ NamedClockList *ncl = qdev_get_clocklist(dev, name);
+ Clock *clk = ncl->clock;
- ncl = qdev_get_clocklist(dev, name);
+ ncl = qdev_init_clocklist(alias_dev, alias_name, true, ncl->output, clk);
- qdev_init_clocklist(alias_dev, alias_name, ncl->output, ncl->clock);
+ object_property_add_link(OBJECT(alias_dev), alias_name,
+ TYPE_CLOCK,
+ (Object **) &ncl->clock,
+ NULL, OBJ_PROP_LINK_STRONG);
+ /*
+ * Since the link property has the OBJ_PROP_LINK_STRONG flag, the clk
+ * object reference count gets decremented on property deletion.
+ * However object_property_add_link does not increment it since it
+ * doesn't know the linked object. Increment it here to ensure the
+ * aliased clock stays alive during this device life-time.
+ */
+ object_ref(OBJECT(clk));
- return ncl->clock;
+ return clk;
}
void qdev_connect_clock_in(DeviceState *dev, const char *name, Clock *source)
diff --git a/hw/core/qdev-hotplug.c b/hw/core/qdev-hotplug.c
index d495d0e..ff176dc 100644
--- a/hw/core/qdev-hotplug.c
+++ b/hw/core/qdev-hotplug.c
@@ -12,6 +12,7 @@
#include "qemu/osdep.h"
#include "hw/qdev-core.h"
#include "hw/boards.h"
+#include "qapi/error.h"
HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev)
{
@@ -30,12 +31,48 @@ HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev)
return NULL;
}
-bool qdev_hotplug_allowed(DeviceState *dev, Error **errp)
+static bool qdev_hotplug_unplug_allowed_common(DeviceState *dev, BusState *bus,
+ Error **errp)
+{
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
+
+ if (!dc->hotpluggable) {
+ error_setg(errp, "Device '%s' does not support hotplugging",
+ object_get_typename(OBJECT(dev)));
+ return false;
+ }
+
+ if (bus) {
+ if (!qbus_is_hotpluggable(bus)) {
+ error_setg(errp, "Bus '%s' does not support hotplugging",
+ bus->name);
+ return false;
+ }
+ } else {
+ if (!qdev_get_machine_hotplug_handler(dev)) {
+ /*
+ * No bus, no machine hotplug handler --> device is not hotpluggable
+ */
+ error_setg(errp,
+ "Device '%s' can not be hotplugged on this machine",
+ object_get_typename(OBJECT(dev)));
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool qdev_hotplug_allowed(DeviceState *dev, BusState *bus, Error **errp)
{
MachineState *machine;
MachineClass *mc;
Object *m_obj = qdev_get_machine();
+ if (!qdev_hotplug_unplug_allowed_common(dev, bus, errp)) {
+ return false;
+ }
+
if (object_dynamic_cast(m_obj, TYPE_MACHINE)) {
machine = MACHINE(m_obj);
mc = MACHINE_GET_CLASS(machine);
@@ -47,6 +84,12 @@ bool qdev_hotplug_allowed(DeviceState *dev, Error **errp)
return true;
}
+bool qdev_hotunplug_allowed(DeviceState *dev, Error **errp)
+{
+ return !qdev_unplug_blocked(dev, errp) &&
+ qdev_hotplug_unplug_allowed_common(dev, dev->parent_bus, errp);
+}
+
HotplugHandler *qdev_get_bus_hotplug_handler(DeviceState *dev)
{
if (dev->parent_bus) {
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index f13350b..24e145d 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -29,8 +29,8 @@
#include "audio/audio.h"
#include "chardev/char-fe.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
+#include "system/block-backend.h"
+#include "system/blockdev.h"
#include "net/net.h"
#include "hw/pci/pci.h"
#include "hw/pci/pcie.h"
@@ -58,13 +58,39 @@ static bool check_prop_still_unset(Object *obj, const char *name,
return false;
}
+bool qdev_prop_sanitize_s390x_loadparm(uint8_t *loadparm, const char *str,
+ Error **errp)
+{
+ int i, len;
+
+ len = strlen(str);
+ if (len > 8) {
+ error_setg(errp, "'loadparm' can only contain up to 8 characters");
+ return false;
+ }
+
+ for (i = 0; i < len; i++) {
+ uint8_t c = qemu_toupper(str[i]); /* mimic HMC */
+
+ if (qemu_isalnum(c) || c == '.' || c == ' ') {
+ loadparm[i] = c;
+ } else {
+ error_setg(errp,
+ "invalid character in 'loadparm': '%c' (ASCII 0x%02x)",
+ c, c);
+ return false;
+ }
+ }
+
+ return true;
+}
/* --- drive --- */
static void get_drive(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
void **ptr = object_field_prop_ptr(obj, prop);
const char *value;
char *p;
@@ -90,7 +116,7 @@ static void set_drive_helper(Object *obj, Visitor *v, const char *name,
void *opaque, bool iothread, Error **errp)
{
DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
+ const Property *prop = opaque;
void **ptr = object_field_prop_ptr(obj, prop);
char *str;
BlockBackend *blk;
@@ -119,6 +145,7 @@ static void set_drive_helper(Object *obj, Visitor *v, const char *name,
if (ctx != bdrv_get_aio_context(bs)) {
error_setg(errp, "Different aio context is not supported for new "
"node");
+ return;
}
blk_replace_bs(blk, bs, errp);
@@ -199,7 +226,7 @@ static void set_drive_iothread(Object *obj, Visitor *v, const char *name,
static void release_drive(Object *obj, const char *name, void *opaque)
{
DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
+ const Property *prop = opaque;
BlockBackend **ptr = object_field_prop_ptr(obj, prop);
if (*ptr) {
@@ -209,7 +236,7 @@ static void release_drive(Object *obj, const char *name, void *opaque)
}
const PropertyInfo qdev_prop_drive = {
- .name = "str",
+ .type = "str",
.description = "Node name or ID of a block device to use as a backend",
.realized_set_allowed = true,
.get = get_drive,
@@ -218,7 +245,7 @@ const PropertyInfo qdev_prop_drive = {
};
const PropertyInfo qdev_prop_drive_iothread = {
- .name = "str",
+ .type = "str",
.description = "Node name or ID of a block device to use as a backend",
.realized_set_allowed = true,
.get = get_drive,
@@ -243,7 +270,7 @@ static void set_chr(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
ERRP_GUARD();
- Property *prop = opaque;
+ const Property *prop = opaque;
CharBackend *be = object_field_prop_ptr(obj, prop);
Chardev *s;
char *str;
@@ -279,14 +306,14 @@ static void set_chr(Object *obj, Visitor *v, const char *name, void *opaque,
static void release_chr(Object *obj, const char *name, void *opaque)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
CharBackend *be = object_field_prop_ptr(obj, prop);
qemu_chr_fe_deinit(be, false);
}
const PropertyInfo qdev_prop_chr = {
- .name = "str",
+ .type = "str",
.description = "ID of a chardev to use as a backend",
.get = get_chr,
.set = set_chr,
@@ -303,7 +330,7 @@ const PropertyInfo qdev_prop_chr = {
static void get_mac(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
MACAddr *mac = object_field_prop_ptr(obj, prop);
char buffer[2 * 6 + 5 + 1];
char *p = buffer;
@@ -318,7 +345,7 @@ static void get_mac(Object *obj, Visitor *v, const char *name, void *opaque,
static void set_mac(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
MACAddr *mac = object_field_prop_ptr(obj, prop);
int i, pos;
char *str;
@@ -360,7 +387,7 @@ inval:
}
const PropertyInfo qdev_prop_macaddr = {
- .name = "str",
+ .type = "str",
.description = "Ethernet 6-byte MAC Address, example: 52:54:00:12:34:56",
.get = get_mac,
.set = set_mac,
@@ -380,7 +407,7 @@ void qdev_prop_set_macaddr(DeviceState *dev, const char *name,
static void get_netdev(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
NICPeers *peers_ptr = object_field_prop_ptr(obj, prop);
char *p = g_strdup(peers_ptr->ncs[0] ? peers_ptr->ncs[0]->name : "");
@@ -391,7 +418,7 @@ static void get_netdev(Object *obj, Visitor *v, const char *name,
static void set_netdev(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
NICPeers *peers_ptr = object_field_prop_ptr(obj, prop);
NetClientState **ncs = peers_ptr->ncs;
NetClientState *peers[MAX_QUEUE_NUM];
@@ -448,7 +475,7 @@ out:
}
const PropertyInfo qdev_prop_netdev = {
- .name = "str",
+ .type = "str",
.description = "ID of a netdev to use as a backend",
.get = get_netdev,
.set = set_netdev,
@@ -459,7 +486,7 @@ const PropertyInfo qdev_prop_netdev = {
static void get_audiodev(Object *obj, Visitor *v, const char* name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
QEMUSoundCard *card = object_field_prop_ptr(obj, prop);
char *p = g_strdup(audio_get_id(card));
@@ -470,7 +497,7 @@ static void get_audiodev(Object *obj, Visitor *v, const char* name,
static void set_audiodev(Object *obj, Visitor *v, const char* name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
QEMUSoundCard *card = object_field_prop_ptr(obj, prop);
AudioState *state;
g_autofree char *str = NULL;
@@ -486,7 +513,7 @@ static void set_audiodev(Object *obj, Visitor *v, const char* name,
}
const PropertyInfo qdev_prop_audiodev = {
- .name = "str",
+ .type = "str",
.description = "ID of an audiodev to use as a backend",
/* release done on shutdown */
.get = get_audiodev,
@@ -552,7 +579,7 @@ static void qdev_propinfo_set_losttickpolicy(Object *obj, Visitor *v,
const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
int *ptr = object_field_prop_ptr(obj, prop);
int value;
@@ -576,7 +603,8 @@ static void qdev_propinfo_set_losttickpolicy(Object *obj, Visitor *v,
QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int));
const PropertyInfo qdev_prop_losttickpolicy = {
- .name = "LostTickPolicy",
+ .type = "LostTickPolicy",
+ .description = "Policy for handling lost ticks (discard/delay/slew)",
.enum_table = &LostTickPolicy_lookup,
.get = qdev_propinfo_get_enum,
.set = qdev_propinfo_set_losttickpolicy,
@@ -588,25 +616,21 @@ const PropertyInfo qdev_prop_losttickpolicy = {
static void set_blocksize(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- DeviceState *dev = DEVICE(obj);
- Property *prop = opaque;
+ const Property *prop = opaque;
uint32_t *ptr = object_field_prop_ptr(obj, prop);
uint64_t value;
- Error *local_err = NULL;
if (!visit_type_size(v, name, &value, errp)) {
return;
}
- check_block_size(dev->id ? : "", name, value, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
+ if (!check_block_size(name, value, errp)) {
return;
}
*ptr = value;
}
const PropertyInfo qdev_prop_blocksize = {
- .name = "size",
+ .type = "size",
.description = "A power of two between " MIN_BLOCK_SIZE_STR
" and " MAX_BLOCK_SIZE_STR,
.get = qdev_propinfo_get_size32,
@@ -619,9 +643,8 @@ const PropertyInfo qdev_prop_blocksize = {
QEMU_BUILD_BUG_ON(sizeof(BlockdevOnError) != sizeof(int));
const PropertyInfo qdev_prop_blockdev_on_error = {
- .name = "BlockdevOnError",
- .description = "Error handling policy, "
- "report/ignore/enospc/stop/auto",
+ .type = "BlockdevOnError",
+ .description = "Error handling policy (report/ignore/enospc/stop/auto)",
.enum_table = &BlockdevOnError_lookup,
.get = qdev_propinfo_get_enum,
.set = qdev_propinfo_set_enum,
@@ -633,9 +656,9 @@ const PropertyInfo qdev_prop_blockdev_on_error = {
QEMU_BUILD_BUG_ON(sizeof(BiosAtaTranslation) != sizeof(int));
const PropertyInfo qdev_prop_bios_chs_trans = {
- .name = "BiosAtaTranslation",
- .description = "Logical CHS translation algorithm, "
- "auto/none/lba/large/rechs",
+ .type = "BiosAtaTranslation",
+ .description = "Logical CHS translation algorithm "
+ " (auto/none/lba/large/rechs)",
.enum_table = &BiosAtaTranslation_lookup,
.get = qdev_propinfo_get_enum,
.set = qdev_propinfo_set_enum,
@@ -645,9 +668,8 @@ const PropertyInfo qdev_prop_bios_chs_trans = {
/* --- FDC default drive types */
const PropertyInfo qdev_prop_fdc_drive_type = {
- .name = "FdcDriveType",
- .description = "FDC drive type, "
- "144/288/120/none/auto",
+ .type = "FloppyDriveType",
+ .description = "Floppy drive type (144/288/120/none/auto)",
.enum_table = &FloppyDriveType_lookup,
.get = qdev_propinfo_get_enum,
.set = qdev_propinfo_set_enum,
@@ -657,9 +679,9 @@ const PropertyInfo qdev_prop_fdc_drive_type = {
/* --- MultiFDCompression --- */
const PropertyInfo qdev_prop_multifd_compression = {
- .name = "MultiFDCompression",
- .description = "multifd_compression values, "
- "none/zlib/zstd/qpl/uadk",
+ .type = "MultiFDCompression",
+ .description = "multifd_compression values"
+ " (none/zlib/zstd/qpl/uadk/qatzip)",
.enum_table = &MultiFDCompression_lookup,
.get = qdev_propinfo_get_enum,
.set = qdev_propinfo_set_enum,
@@ -671,9 +693,8 @@ const PropertyInfo qdev_prop_multifd_compression = {
QEMU_BUILD_BUG_ON(sizeof(MigMode) != sizeof(int));
const PropertyInfo qdev_prop_mig_mode = {
- .name = "MigMode",
- .description = "mig_mode values, "
- "normal,cpr-reboot",
+ .type = "MigMode",
+ .description = "Migration mode (normal/cpr-reboot)",
.enum_table = &MigMode_lookup,
.get = qdev_propinfo_get_enum,
.set = qdev_propinfo_set_enum,
@@ -685,9 +706,8 @@ const PropertyInfo qdev_prop_mig_mode = {
QEMU_BUILD_BUG_ON(sizeof(GranuleMode) != sizeof(int));
const PropertyInfo qdev_prop_granule_mode = {
- .name = "GranuleMode",
- .description = "granule_mode values, "
- "4k, 8k, 16k, 64k, host",
+ .type = "GranuleMode",
+ .description = "Granule page size (4k/8k/16k/64k/host)",
.enum_table = &GranuleMode_lookup,
.get = qdev_propinfo_get_enum,
.set = qdev_propinfo_set_enum,
@@ -695,9 +715,8 @@ const PropertyInfo qdev_prop_granule_mode = {
};
const PropertyInfo qdev_prop_zero_page_detection = {
- .name = "ZeroPageDetection",
- .description = "zero_page_detection values, "
- "none,legacy,multifd",
+ .type = "ZeroPageDetection",
+ .description = "Zero page detection (none/legacy/multifd)",
.enum_table = &ZeroPageDetection_lookup,
.get = qdev_propinfo_get_enum,
.set = qdev_propinfo_set_enum,
@@ -715,7 +734,7 @@ const PropertyInfo qdev_prop_zero_page_detection = {
static void get_reserved_region(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
ReservedRegion *rr = object_field_prop_ptr(obj, prop);
char buffer[64];
char *p = buffer;
@@ -731,7 +750,7 @@ static void get_reserved_region(Object *obj, Visitor *v, const char *name,
static void set_reserved_region(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
ReservedRegion *rr = object_field_prop_ptr(obj, prop);
const char *endptr;
uint64_t lob, upb;
@@ -775,11 +794,10 @@ separator_error:
error_setg(errp, "reserved region fields must be separated with ':'");
out:
g_free(str);
- return;
}
const PropertyInfo qdev_prop_reserved_region = {
- .name = "reserved_region",
+ .type = "str",
.description = "Reserved Region, example: 0xFEE00000:0xFEEFFFFF:0",
.get = get_reserved_region,
.set = set_reserved_region,
@@ -793,43 +811,61 @@ const PropertyInfo qdev_prop_reserved_region = {
static void set_pci_devfn(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
+ g_autofree GenericAlternate *alt;
int32_t value, *ptr = object_field_prop_ptr(obj, prop);
unsigned int slot, fn, n;
- char *str;
+ g_autofree char *str = NULL;
+
+ if (!visit_start_alternate(v, name, &alt, sizeof(*alt), errp)) {
+ return;
+ }
+
+ switch (alt->type) {
+ case QTYPE_QSTRING:
+ if (!visit_type_str(v, name, &str, errp)) {
+ goto out;
+ }
- if (!visit_type_str(v, name, &str, NULL)) {
+ if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) {
+ fn = 0;
+ if (sscanf(str, "%x%n", &slot, &n) != 1) {
+ goto invalid;
+ }
+ }
+ if (str[n] != '\0' || fn > 7 || slot > 31) {
+ goto invalid;
+ }
+ *ptr = slot << 3 | fn;
+ break;
+
+ case QTYPE_QNUM:
if (!visit_type_int32(v, name, &value, errp)) {
- return;
+ goto out;
}
if (value < -1 || value > 255) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
name ? name : "null", "a value between -1 and 255");
- return;
+ goto out;
}
*ptr = value;
- return;
- }
+ break;
- if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) {
- fn = 0;
- if (sscanf(str, "%x%n", &slot, &n) != 1) {
- goto invalid;
- }
- }
- if (str[n] != '\0' || fn > 7 || slot > 31) {
- goto invalid;
+ default:
+ error_setg(errp, "Invalid parameter type for '%s', expected int or str",
+ name ? name : "null");
+ goto out;
}
- *ptr = slot << 3 | fn;
- g_free(str);
- return;
+
+ goto out;
invalid:
error_set_from_qdev_prop_error(errp, EINVAL, obj, name, str);
- g_free(str);
+out:
+ visit_end_alternate(v, (void **) &alt);
}
-static int print_pci_devfn(Object *obj, Property *prop, char *dest,
+static int print_pci_devfn(Object *obj, const Property *prop, char *dest,
size_t len)
{
int32_t *ptr = object_field_prop_ptr(obj, prop);
@@ -842,7 +878,7 @@ static int print_pci_devfn(Object *obj, Property *prop, char *dest,
}
const PropertyInfo qdev_prop_pci_devfn = {
- .name = "int32",
+ .type = "str",
.description = "Slot and optional function number, example: 06.0 or 06",
.print = print_pci_devfn,
.get = qdev_propinfo_get_int32,
@@ -855,7 +891,7 @@ const PropertyInfo qdev_prop_pci_devfn = {
static void get_pci_host_devaddr(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
PCIHostDeviceAddress *addr = object_field_prop_ptr(obj, prop);
char buffer[] = "ffff:ff:ff.f";
char *p = buffer;
@@ -881,7 +917,7 @@ static void get_pci_host_devaddr(Object *obj, Visitor *v, const char *name,
static void set_pci_host_devaddr(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
PCIHostDeviceAddress *addr = object_field_prop_ptr(obj, prop);
char *str, *p;
char *e;
@@ -948,8 +984,8 @@ inval:
}
const PropertyInfo qdev_prop_pci_host_devaddr = {
- .name = "str",
- .description = "Address (bus/device/function) of "
+ .type = "str",
+ .description = "Address (bus:device.function) of "
"the host device, example: 04:10.0",
.get = get_pci_host_devaddr,
.set = set_pci_host_devaddr,
@@ -958,7 +994,7 @@ const PropertyInfo qdev_prop_pci_host_devaddr = {
/* --- OffAutoPCIBAR off/auto/bar0/bar1/bar2/bar3/bar4/bar5 --- */
const PropertyInfo qdev_prop_off_auto_pcibar = {
- .name = "OffAutoPCIBAR",
+ .type = "OffAutoPCIBAR",
.description = "off/auto/bar0/bar1/bar2/bar3/bar4/bar5",
.enum_table = &OffAutoPCIBAR_lookup,
.get = qdev_propinfo_get_enum,
@@ -971,7 +1007,7 @@ const PropertyInfo qdev_prop_off_auto_pcibar = {
static void get_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
PCIExpLinkSpeed *p = object_field_prop_ptr(obj, prop);
int speed;
@@ -1005,7 +1041,7 @@ static void get_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
static void set_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
PCIExpLinkSpeed *p = object_field_prop_ptr(obj, prop);
int speed;
@@ -1040,7 +1076,7 @@ static void set_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
}
const PropertyInfo qdev_prop_pcie_link_speed = {
- .name = "PCIELinkSpeed",
+ .type = "PCIELinkSpeed",
.description = "2_5/5/8/16/32/64",
.enum_table = &PCIELinkSpeed_lookup,
.get = get_prop_pcielinkspeed,
@@ -1053,7 +1089,7 @@ const PropertyInfo qdev_prop_pcie_link_speed = {
static void get_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
PCIExpLinkWidth *p = object_field_prop_ptr(obj, prop);
int width;
@@ -1090,7 +1126,7 @@ static void get_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
static void set_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
PCIExpLinkWidth *p = object_field_prop_ptr(obj, prop);
int width;
@@ -1128,7 +1164,7 @@ static void set_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
}
const PropertyInfo qdev_prop_pcie_link_width = {
- .name = "PCIELinkWidth",
+ .type = "PCIELinkWidth",
.description = "1/2/4/8/12/16/32",
.enum_table = &PCIELinkWidth_lookup,
.get = get_prop_pcielinkwidth,
@@ -1141,7 +1177,7 @@ const PropertyInfo qdev_prop_pcie_link_width = {
static void get_uuid(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
QemuUUID *uuid = object_field_prop_ptr(obj, prop);
char buffer[UUID_STR_LEN];
char *p = buffer;
@@ -1156,7 +1192,7 @@ static void get_uuid(Object *obj, Visitor *v, const char *name, void *opaque,
static void set_uuid(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
QemuUUID *uuid = object_field_prop_ptr(obj, prop);
char *str;
@@ -1178,7 +1214,7 @@ static void set_default_uuid_auto(ObjectProperty *op, const Property *prop)
}
const PropertyInfo qdev_prop_uuid = {
- .name = "str",
+ .type = "str",
.description = "UUID (aka GUID) or \"" UUID_VALUE_AUTO
"\" for random value (default)",
.get = get_uuid,
@@ -1188,12 +1224,12 @@ const PropertyInfo qdev_prop_uuid = {
/* --- s390 cpu entitlement policy --- */
-QEMU_BUILD_BUG_ON(sizeof(CpuS390Entitlement) != sizeof(int));
+QEMU_BUILD_BUG_ON(sizeof(S390CpuEntitlement) != sizeof(int));
const PropertyInfo qdev_prop_cpus390entitlement = {
- .name = "CpuS390Entitlement",
- .description = "low/medium (default)/high",
- .enum_table = &CpuS390Entitlement_lookup,
+ .type = "S390CpuEntitlement",
+ .description = "auto/low/medium/high (default medium)",
+ .enum_table = &S390CpuEntitlement_lookup,
.get = qdev_propinfo_get_enum,
.set = qdev_propinfo_set_enum,
.set_default_value = qdev_propinfo_set_default_value_enum,
@@ -1236,10 +1272,30 @@ static void release_iothread_vq_mapping_list(Object *obj,
}
const PropertyInfo qdev_prop_iothread_vq_mapping_list = {
- .name = "IOThreadVirtQueueMappingList",
+ .type = "IOThreadVirtQueueMappingList",
.description = "IOThread virtqueue mapping list [{\"iothread\":\"<id>\", "
"\"vqs\":[1,2,3,...]},...]",
.get = get_iothread_vq_mapping_list,
.set = set_iothread_vq_mapping_list,
.release = release_iothread_vq_mapping_list,
};
+
+/* --- Endian modes */
+
+const PropertyInfo qdev_prop_endian_mode = {
+ .type = "EndianMode",
+ .description = "Endian mode, big/little/unspecified",
+ .enum_table = &EndianMode_lookup,
+ .get = qdev_propinfo_get_enum,
+ .set = qdev_propinfo_set_enum,
+ .set_default_value = qdev_propinfo_set_default_value_enum,
+};
+
+const PropertyInfo qdev_prop_vmapple_virtio_blk_variant = {
+ .type = "VMAppleVirtioBlkVariant",
+ .description = "unspecified/root/aux",
+ .enum_table = &VMAppleVirtioBlkVariant_lookup,
+ .get = qdev_propinfo_get_enum,
+ .set = qdev_propinfo_set_enum,
+ .set_default_value = qdev_propinfo_set_default_value_enum,
+};
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index 86a5835..147b3ff 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -2,7 +2,7 @@
#include "hw/qdev-properties.h"
#include "qapi/error.h"
#include "qapi/qapi-types-misc.h"
-#include "qapi/qmp/qlist.h"
+#include "qobject/qlist.h"
#include "qemu/ctype.h"
#include "qemu/error-report.h"
#include "qapi/visitor.h"
@@ -51,7 +51,7 @@ void qdev_prop_allow_set_link_before_realize(const Object *obj,
}
}
-void *object_field_prop_ptr(Object *obj, Property *prop)
+void *object_field_prop_ptr(Object *obj, const Property *prop)
{
void *ptr = obj;
ptr += prop->offset;
@@ -61,7 +61,7 @@ void *object_field_prop_ptr(Object *obj, Property *prop)
static void field_prop_get(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
return prop->info->get(obj, v, name, opaque, errp);
}
@@ -78,7 +78,7 @@ static ObjectPropertyAccessor *field_prop_getter(const PropertyInfo *info)
static void field_prop_set(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
if (!qdev_prop_allow_set(obj, name, prop->info, errp)) {
return;
@@ -100,7 +100,7 @@ static ObjectPropertyAccessor *field_prop_setter(const PropertyInfo *info)
void qdev_propinfo_get_enum(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
int *ptr = object_field_prop_ptr(obj, prop);
visit_type_enum(v, name, ptr, prop->info->enum_table, errp);
@@ -109,7 +109,7 @@ void qdev_propinfo_get_enum(Object *obj, Visitor *v, const char *name,
void qdev_propinfo_set_enum(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
int *ptr = object_field_prop_ptr(obj, prop);
visit_type_enum(v, name, ptr, prop->info->enum_table, errp);
@@ -122,22 +122,15 @@ void qdev_propinfo_set_default_value_enum(ObjectProperty *op,
qapi_enum_lookup(prop->info->enum_table, prop->defval.i));
}
-const PropertyInfo qdev_prop_enum = {
- .name = "enum",
- .get = qdev_propinfo_get_enum,
- .set = qdev_propinfo_set_enum,
- .set_default_value = qdev_propinfo_set_default_value_enum,
-};
-
/* Bit */
-static uint32_t qdev_get_prop_mask(Property *prop)
+static uint32_t qdev_get_prop_mask(const Property *prop)
{
assert(prop->info == &qdev_prop_bit);
return 0x1 << prop->bitnr;
}
-static void bit_prop_set(Object *obj, Property *props, bool val)
+static void bit_prop_set(Object *obj, const Property *props, bool val)
{
uint32_t *p = object_field_prop_ptr(obj, props);
uint32_t mask = qdev_get_prop_mask(props);
@@ -151,7 +144,7 @@ static void bit_prop_set(Object *obj, Property *props, bool val)
static void prop_get_bit(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint32_t *p = object_field_prop_ptr(obj, prop);
bool value = (*p & qdev_get_prop_mask(prop)) != 0;
@@ -161,7 +154,7 @@ static void prop_get_bit(Object *obj, Visitor *v, const char *name,
static void prop_set_bit(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
bool value;
if (!visit_type_bool(v, name, &value, errp)) {
@@ -176,7 +169,7 @@ static void set_default_value_bool(ObjectProperty *op, const Property *prop)
}
const PropertyInfo qdev_prop_bit = {
- .name = "bool",
+ .type = "bool",
.description = "on/off",
.get = prop_get_bit,
.set = prop_set_bit,
@@ -185,13 +178,13 @@ const PropertyInfo qdev_prop_bit = {
/* Bit64 */
-static uint64_t qdev_get_prop_mask64(Property *prop)
+static uint64_t qdev_get_prop_mask64(const Property *prop)
{
assert(prop->info == &qdev_prop_bit64);
return 0x1ull << prop->bitnr;
}
-static void bit64_prop_set(Object *obj, Property *props, bool val)
+static void bit64_prop_set(Object *obj, const Property *props, bool val)
{
uint64_t *p = object_field_prop_ptr(obj, props);
uint64_t mask = qdev_get_prop_mask64(props);
@@ -205,7 +198,7 @@ static void bit64_prop_set(Object *obj, Property *props, bool val)
static void prop_get_bit64(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint64_t *p = object_field_prop_ptr(obj, prop);
bool value = (*p & qdev_get_prop_mask64(prop)) != 0;
@@ -215,7 +208,7 @@ static void prop_get_bit64(Object *obj, Visitor *v, const char *name,
static void prop_set_bit64(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
bool value;
if (!visit_type_bool(v, name, &value, errp)) {
@@ -225,7 +218,7 @@ static void prop_set_bit64(Object *obj, Visitor *v, const char *name,
}
const PropertyInfo qdev_prop_bit64 = {
- .name = "bool",
+ .type = "bool",
.description = "on/off",
.get = prop_get_bit64,
.set = prop_set_bit64,
@@ -237,7 +230,7 @@ const PropertyInfo qdev_prop_bit64 = {
static void get_bool(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
bool *ptr = object_field_prop_ptr(obj, prop);
visit_type_bool(v, name, ptr, errp);
@@ -246,14 +239,15 @@ static void get_bool(Object *obj, Visitor *v, const char *name, void *opaque,
static void set_bool(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
bool *ptr = object_field_prop_ptr(obj, prop);
visit_type_bool(v, name, ptr, errp);
}
const PropertyInfo qdev_prop_bool = {
- .name = "bool",
+ .type = "bool",
+ .description = "on/off",
.get = get_bool,
.set = set_bool,
.set_default_value = set_default_value_bool,
@@ -264,7 +258,7 @@ const PropertyInfo qdev_prop_bool = {
static void get_uint8(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint8_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_uint8(v, name, ptr, errp);
@@ -273,7 +267,7 @@ static void get_uint8(Object *obj, Visitor *v, const char *name, void *opaque,
static void set_uint8(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint8_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_uint8(v, name, ptr, errp);
@@ -292,7 +286,7 @@ void qdev_propinfo_set_default_value_uint(ObjectProperty *op,
}
const PropertyInfo qdev_prop_uint8 = {
- .name = "uint8",
+ .type = "uint8",
.get = get_uint8,
.set = set_uint8,
.set_default_value = qdev_propinfo_set_default_value_uint,
@@ -303,7 +297,7 @@ const PropertyInfo qdev_prop_uint8 = {
static void get_uint16(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint16_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_uint16(v, name, ptr, errp);
@@ -312,14 +306,14 @@ static void get_uint16(Object *obj, Visitor *v, const char *name,
static void set_uint16(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint16_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_uint16(v, name, ptr, errp);
}
const PropertyInfo qdev_prop_uint16 = {
- .name = "uint16",
+ .type = "uint16",
.get = get_uint16,
.set = set_uint16,
.set_default_value = qdev_propinfo_set_default_value_uint,
@@ -330,7 +324,7 @@ const PropertyInfo qdev_prop_uint16 = {
static void get_uint32(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint32_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_uint32(v, name, ptr, errp);
@@ -339,7 +333,7 @@ static void get_uint32(Object *obj, Visitor *v, const char *name,
static void set_uint32(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint32_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_uint32(v, name, ptr, errp);
@@ -348,7 +342,7 @@ static void set_uint32(Object *obj, Visitor *v, const char *name,
void qdev_propinfo_get_int32(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
int32_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_int32(v, name, ptr, errp);
@@ -357,21 +351,21 @@ void qdev_propinfo_get_int32(Object *obj, Visitor *v, const char *name,
static void set_int32(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
int32_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_int32(v, name, ptr, errp);
}
const PropertyInfo qdev_prop_uint32 = {
- .name = "uint32",
+ .type = "uint32",
.get = get_uint32,
.set = set_uint32,
.set_default_value = qdev_propinfo_set_default_value_uint,
};
const PropertyInfo qdev_prop_int32 = {
- .name = "int32",
+ .type = "int32",
.get = qdev_propinfo_get_int32,
.set = set_int32,
.set_default_value = qdev_propinfo_set_default_value_int,
@@ -382,7 +376,7 @@ const PropertyInfo qdev_prop_int32 = {
static void get_uint64(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint64_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_uint64(v, name, ptr, errp);
@@ -391,7 +385,7 @@ static void get_uint64(Object *obj, Visitor *v, const char *name,
static void set_uint64(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint64_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_uint64(v, name, ptr, errp);
@@ -400,7 +394,7 @@ static void set_uint64(Object *obj, Visitor *v, const char *name,
static void get_int64(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
int64_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_int64(v, name, ptr, errp);
@@ -409,21 +403,21 @@ static void get_int64(Object *obj, Visitor *v, const char *name,
static void set_int64(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
int64_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_int64(v, name, ptr, errp);
}
const PropertyInfo qdev_prop_uint64 = {
- .name = "uint64",
+ .type = "uint64",
.get = get_uint64,
.set = set_uint64,
.set_default_value = qdev_propinfo_set_default_value_uint,
};
const PropertyInfo qdev_prop_int64 = {
- .name = "int64",
+ .type = "int64",
.get = get_int64,
.set = set_int64,
.set_default_value = qdev_propinfo_set_default_value_int,
@@ -432,7 +426,7 @@ const PropertyInfo qdev_prop_int64 = {
static void set_uint64_checkmask(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint64_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_uint64(v, name, ptr, errp);
@@ -443,23 +437,60 @@ static void set_uint64_checkmask(Object *obj, Visitor *v, const char *name,
}
const PropertyInfo qdev_prop_uint64_checkmask = {
- .name = "uint64",
+ .type = "uint64",
.get = get_uint64,
.set = set_uint64_checkmask,
};
+/* --- pointer-size integer --- */
+
+static void get_usize(Object *obj, Visitor *v, const char *name, void *opaque,
+ Error **errp)
+{
+ const Property *prop = opaque;
+
+#if HOST_LONG_BITS == 32
+ uint32_t *ptr = object_field_prop_ptr(obj, prop);
+ visit_type_uint32(v, name, ptr, errp);
+#else
+ uint64_t *ptr = object_field_prop_ptr(obj, prop);
+ visit_type_uint64(v, name, ptr, errp);
+#endif
+}
+
+static void set_usize(Object *obj, Visitor *v, const char *name, void *opaque,
+ Error **errp)
+{
+ const Property *prop = opaque;
+
+#if HOST_LONG_BITS == 32
+ uint32_t *ptr = object_field_prop_ptr(obj, prop);
+ visit_type_uint32(v, name, ptr, errp);
+#else
+ uint64_t *ptr = object_field_prop_ptr(obj, prop);
+ visit_type_uint64(v, name, ptr, errp);
+#endif
+}
+
+const PropertyInfo qdev_prop_usize = {
+ .type = "usize",
+ .get = get_usize,
+ .set = set_usize,
+ .set_default_value = qdev_propinfo_set_default_value_uint,
+};
+
/* --- string --- */
static void release_string(Object *obj, const char *name, void *opaque)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
g_free(*(char **)object_field_prop_ptr(obj, prop));
}
static void get_string(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
char **ptr = object_field_prop_ptr(obj, prop);
if (!*ptr) {
@@ -473,7 +504,7 @@ static void get_string(Object *obj, Visitor *v, const char *name,
static void set_string(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
char **ptr = object_field_prop_ptr(obj, prop);
char *str;
@@ -485,7 +516,7 @@ static void set_string(Object *obj, Visitor *v, const char *name,
}
const PropertyInfo qdev_prop_string = {
- .name = "str",
+ .type = "str",
.release = release_string,
.get = get_string,
.set = set_string,
@@ -494,7 +525,7 @@ const PropertyInfo qdev_prop_string = {
/* --- on/off/auto --- */
const PropertyInfo qdev_prop_on_off_auto = {
- .name = "OnOffAuto",
+ .type = "OnOffAuto",
.description = "on/off/auto",
.enum_table = &OnOffAuto_lookup,
.get = qdev_propinfo_get_enum,
@@ -507,7 +538,7 @@ const PropertyInfo qdev_prop_on_off_auto = {
void qdev_propinfo_get_size32(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint32_t *ptr = object_field_prop_ptr(obj, prop);
uint64_t value = *ptr;
@@ -517,7 +548,7 @@ void qdev_propinfo_get_size32(Object *obj, Visitor *v, const char *name,
static void set_size32(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint32_t *ptr = object_field_prop_ptr(obj, prop);
uint64_t value;
@@ -537,7 +568,7 @@ static void set_size32(Object *obj, Visitor *v, const char *name, void *opaque,
}
const PropertyInfo qdev_prop_size32 = {
- .name = "size",
+ .type = "size",
.get = qdev_propinfo_get_size32,
.set = set_size32,
.set_default_value = qdev_propinfo_set_default_value_uint,
@@ -557,7 +588,7 @@ struct ArrayElementList {
* specific element of the array. Arrays are backed by an uint32_t length field
* and an element array. @elem points at an element in this element array.
*/
-static Property array_elem_prop(Object *obj, Property *parent_prop,
+static Property array_elem_prop(Object *obj, const Property *parent_prop,
const char *name, char *elem)
{
return (Property) {
@@ -582,7 +613,7 @@ static Property array_elem_prop(Object *obj, Property *parent_prop,
*/
static void release_prop_array(Object *obj, const char *name, void *opaque)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint32_t *alenptr = object_field_prop_ptr(obj, prop);
void **arrayptr = (void *)obj + prop->arrayoffset;
char *elem = *arrayptr;
@@ -609,7 +640,7 @@ static void set_prop_array(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
ERRP_GUARD();
- Property *prop = opaque;
+ const Property *prop = opaque;
uint32_t *alenptr = object_field_prop_ptr(obj, prop);
void **arrayptr = (void *)obj + prop->arrayoffset;
ArrayElementList *list, *elem, *next;
@@ -685,7 +716,7 @@ static void get_prop_array(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
ERRP_GUARD();
- Property *prop = opaque;
+ const Property *prop = opaque;
uint32_t *alenptr = object_field_prop_ptr(obj, prop);
void **arrayptr = (void *)obj + prop->arrayoffset;
char *elemptr = *arrayptr;
@@ -740,7 +771,7 @@ static void default_prop_array(ObjectProperty *op, const Property *prop)
}
const PropertyInfo qdev_prop_array = {
- .name = "list",
+ .type = "list",
.get = get_prop_array,
.set = set_prop_array,
.release = release_prop_array,
@@ -749,29 +780,26 @@ const PropertyInfo qdev_prop_array = {
/* --- public helpers --- */
-static Property *qdev_prop_walk(Property *props, const char *name)
+static const Property *qdev_prop_walk(DeviceClass *cls, const char *name)
{
- if (!props) {
- return NULL;
- }
- while (props->name) {
- if (strcmp(props->name, name) == 0) {
- return props;
+ for (int i = 0, n = cls->props_count_; i < n; ++i) {
+ const Property *prop = &cls->props_[i];
+ if (strcmp(prop->name, name) == 0) {
+ return prop;
}
- props++;
}
return NULL;
}
-static Property *qdev_prop_find(DeviceState *dev, const char *name)
+static const Property *qdev_prop_find(DeviceState *dev, const char *name)
{
ObjectClass *class;
- Property *prop;
+ const Property *prop;
/* device properties */
class = object_get_class(OBJECT(dev));
do {
- prop = qdev_prop_walk(DEVICE_CLASS(class)->props_, name);
+ prop = qdev_prop_walk(DEVICE_CLASS(class), name);
if (prop) {
return prop;
}
@@ -840,7 +868,7 @@ void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value)
void qdev_prop_set_enum(DeviceState *dev, const char *name, int value)
{
- Property *prop;
+ const Property *prop;
prop = qdev_prop_find(dev, name);
object_property_set_str(OBJECT(dev), name,
@@ -931,7 +959,7 @@ void qdev_prop_set_globals(DeviceState *dev)
static void get_size(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint64_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_size(v, name, ptr, errp);
@@ -940,14 +968,14 @@ static void get_size(Object *obj, Visitor *v, const char *name, void *opaque,
static void set_size(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
uint64_t *ptr = object_field_prop_ptr(obj, prop);
visit_type_size(v, name, ptr, errp);
}
const PropertyInfo qdev_prop_size = {
- .name = "size",
+ .type = "size",
.get = get_size,
.set = set_size,
.set_default_value = qdev_propinfo_set_default_value_uint,
@@ -956,7 +984,7 @@ const PropertyInfo qdev_prop_size = {
/* --- object link property --- */
static ObjectProperty *create_link_property(ObjectClass *oc, const char *name,
- Property *prop)
+ const Property *prop)
{
return object_class_property_add_link(oc, name, prop->link_type,
prop->offset,
@@ -965,22 +993,22 @@ static ObjectProperty *create_link_property(ObjectClass *oc, const char *name,
}
const PropertyInfo qdev_prop_link = {
- .name = "link",
+ .type = "link",
.create = create_link_property,
};
-void qdev_property_add_static(DeviceState *dev, Property *prop)
+void qdev_property_add_static(DeviceState *dev, const Property *prop)
{
Object *obj = OBJECT(dev);
ObjectProperty *op;
assert(!prop->info->create);
- op = object_property_add(obj, prop->name, prop->info->name,
+ op = object_property_add(obj, prop->name, prop->info->type,
field_prop_getter(prop->info),
field_prop_setter(prop->info),
prop->info->release,
- prop);
+ (Property *)prop);
object_property_set_description(obj, prop->name,
prop->info->description);
@@ -994,7 +1022,7 @@ void qdev_property_add_static(DeviceState *dev, Property *prop)
}
static void qdev_class_add_property(DeviceClass *klass, const char *name,
- Property *prop)
+ const Property *prop)
{
ObjectClass *oc = OBJECT_CLASS(klass);
ObjectProperty *op;
@@ -1003,11 +1031,11 @@ static void qdev_class_add_property(DeviceClass *klass, const char *name,
op = prop->info->create(oc, name, prop);
} else {
op = object_class_property_add(oc,
- name, prop->info->name,
+ name, prop->info->type,
field_prop_getter(prop->info),
field_prop_setter(prop->info),
prop->info->release,
- prop);
+ (Property *)prop);
}
if (prop->set_default) {
prop->info->set_default_value(op, prop);
@@ -1023,7 +1051,7 @@ static void qdev_get_legacy_property(Object *obj, Visitor *v,
const char *name, void *opaque,
Error **errp)
{
- Property *prop = opaque;
+ const Property *prop = opaque;
char buffer[1024];
char *ptr = buffer;
@@ -1046,7 +1074,7 @@ static void qdev_get_legacy_property(Object *obj, Visitor *v,
* Do not use this in new code! QOM Properties added through this interface
* will be given names in the "legacy" namespace.
*/
-static void qdev_class_add_legacy_property(DeviceClass *dc, Property *prop)
+static void qdev_class_add_legacy_property(DeviceClass *dc, const Property *prop)
{
g_autofree char *name = NULL;
@@ -1058,15 +1086,21 @@ static void qdev_class_add_legacy_property(DeviceClass *dc, Property *prop)
name = g_strdup_printf("legacy-%s", prop->name);
object_class_property_add(OBJECT_CLASS(dc), name, "str",
prop->info->print ? qdev_get_legacy_property : prop->info->get,
- NULL, NULL, prop);
+ NULL, NULL, (Property *)prop);
}
-void device_class_set_props(DeviceClass *dc, Property *props)
+void device_class_set_props_n(DeviceClass *dc, const Property *props, size_t n)
{
- Property *prop;
+ /* We used a hole in DeviceClass because that's still a lot. */
+ assert(n <= UINT16_MAX);
+ assert(n != 0);
dc->props_ = props;
- for (prop = props; prop && prop->name; prop++) {
+ dc->props_count_ = n;
+
+ for (size_t i = 0; i < n; ++i) {
+ const Property *prop = &props[i];
+ assert(prop->name);
qdev_class_add_legacy_property(dc, prop);
qdev_class_add_property(dc, prop->name, prop);
}
diff --git a/hw/core/qdev-user.c b/hw/core/qdev-user.c
new file mode 100644
index 0000000..3d421d8
--- /dev/null
+++ b/hw/core/qdev-user.c
@@ -0,0 +1,19 @@
+/*
+ * QDev helpers specific to user emulation.
+ *
+ * Copyright 2025 Linaro, Ltd.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include "qemu/osdep.h"
+#include "qom/object.h"
+#include "hw/qdev-core.h"
+
+void qdev_create_fake_machine(void)
+{
+ Object *fake_machine_obj;
+
+ fake_machine_obj = object_property_add_new_container(object_get_root(),
+ "machine");
+ object_property_add_new_container(fake_machine_obj, "unattached");
+}
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index f3a996f..f600226 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -28,7 +28,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qapi/qapi-events-qdev.h"
-#include "qapi/qmp/qdict.h"
+#include "qobject/qdict.h"
#include "qapi/visitor.h"
#include "qemu/error-report.h"
#include "qemu/option.h"
@@ -146,31 +146,16 @@ bool qdev_set_parent_bus(DeviceState *dev, BusState *bus, Error **errp)
DeviceState *qdev_new(const char *name)
{
- ObjectClass *oc = object_class_by_name(name);
-#ifdef CONFIG_MODULES
- if (!oc) {
- int rv = module_load_qom(name, &error_fatal);
- if (rv > 0) {
- oc = object_class_by_name(name);
- } else {
- error_report("could not find a module for type '%s'", name);
- exit(1);
- }
- }
-#endif
- if (!oc) {
- error_report("unknown type '%s'", name);
- abort();
- }
return DEVICE(object_new(name));
}
DeviceState *qdev_try_new(const char *name)
{
- if (!module_object_class_by_name(name)) {
+ ObjectClass *oc = module_object_class_by_name(name);
+ if (!oc) {
return NULL;
}
- return DEVICE(object_new(name));
+ return DEVICE(object_new_with_class(oc));
}
static QTAILQ_HEAD(, DeviceListener) device_listeners
@@ -491,8 +476,7 @@ static void device_set_realized(Object *obj, bool value, Error **errp)
if (!obj->parent) {
gchar *name = g_strdup_printf("device[%d]", unattached_count++);
- object_property_add_child(container_get(qdev_get_machine(),
- "/unattached"),
+ object_property_add_child(machine_get_container("unattached"),
name, obj);
unattached_parent = true;
g_free(name);
@@ -706,11 +690,10 @@ static void device_finalize(Object *obj)
dev->canonical_path = NULL;
}
- qobject_unref(dev->opts);
g_free(dev->id);
}
-static void device_class_base_init(ObjectClass *class, void *data)
+static void device_class_base_init(ObjectClass *class, const void *data)
{
DeviceClass *klass = DEVICE_CLASS(class);
@@ -718,6 +701,7 @@ static void device_class_base_init(ObjectClass *class, void *data)
* so do not propagate them to the subclasses.
*/
klass->props_ = NULL;
+ klass->props_count_ = 0;
}
static void device_unparent(Object *obj)
@@ -747,58 +731,7 @@ device_vmstate_if_get_id(VMStateIf *obj)
return qdev_get_dev_path(dev);
}
-/**
- * device_phases_reset:
- * Transition reset method for devices to allow moving
- * smoothly from legacy reset method to multi-phases
- */
-static void device_phases_reset(DeviceState *dev)
-{
- ResettableClass *rc = RESETTABLE_GET_CLASS(dev);
-
- if (rc->phases.enter) {
- rc->phases.enter(OBJECT(dev), RESET_TYPE_COLD);
- }
- if (rc->phases.hold) {
- rc->phases.hold(OBJECT(dev), RESET_TYPE_COLD);
- }
- if (rc->phases.exit) {
- rc->phases.exit(OBJECT(dev), RESET_TYPE_COLD);
- }
-}
-
-static void device_transitional_reset(Object *obj)
-{
- DeviceClass *dc = DEVICE_GET_CLASS(obj);
-
- /*
- * This will call either @device_phases_reset (for multi-phases transitioned
- * devices) or a device's specific method for not-yet transitioned devices.
- * In both case, it does not reset children.
- */
- if (dc->reset) {
- dc->reset(DEVICE(obj));
- }
-}
-
-/**
- * device_get_transitional_reset:
- * check if the device's class is ready for multi-phase
- */
-static ResettableTrFunction device_get_transitional_reset(Object *obj)
-{
- DeviceClass *dc = DEVICE_GET_CLASS(obj);
- if (dc->reset != device_phases_reset) {
- /*
- * dc->reset has been overridden by a subclass,
- * the device is not ready for multi phase yet.
- */
- return device_transitional_reset;
- }
- return NULL;
-}
-
-static void device_class_init(ObjectClass *class, void *data)
+static void device_class_init(ObjectClass *class, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(class);
VMStateIfClass *vc = VMSTATE_IF_CLASS(class);
@@ -819,20 +752,12 @@ static void device_class_init(ObjectClass *class, void *data)
rc->child_foreach = device_reset_child_foreach;
/*
- * @device_phases_reset is put as the default reset method below, allowing
- * to do the multi-phase transition from base classes to leaf classes. It
- * allows a legacy-reset Device class to extend a multi-phases-reset
- * Device class for the following reason:
- * + If a base class B has been moved to multi-phase, then it does not
- * override this default reset method and may have defined phase methods.
- * + A child class C (extending class B) which uses
- * device_class_set_parent_reset() (or similar means) to override the
- * reset method will still work as expected. @device_phases_reset function
- * will be registered as the parent reset method and effectively call
- * parent reset phases.
+ * A NULL legacy_reset implies a three-phase reset device. Devices can
+ * only be reset using three-phase aware mechanisms, but we still support
+ * for transitional purposes leaf classes which set the old legacy_reset
+ * method via device_class_set_legacy_reset().
*/
- dc->reset = device_phases_reset;
- rc->get_transitional_function = device_get_transitional_reset;
+ dc->legacy_reset = NULL;
object_class_property_add_bool(class, "realized",
device_get_realized, device_set_realized);
@@ -844,12 +769,30 @@ static void device_class_init(ObjectClass *class, void *data)
offsetof(DeviceState, parent_bus), NULL, 0);
}
-void device_class_set_parent_reset(DeviceClass *dc,
- DeviceReset dev_reset,
- DeviceReset *parent_reset)
+static void do_legacy_reset(Object *obj, ResetType type)
{
- *parent_reset = dc->reset;
- dc->reset = dev_reset;
+ DeviceClass *dc = DEVICE_GET_CLASS(obj);
+
+ dc->legacy_reset(DEVICE(obj));
+}
+
+void device_class_set_legacy_reset(DeviceClass *dc, DeviceReset dev_reset)
+{
+ /*
+ * A legacy DeviceClass::reset has identical semantics to the
+ * three-phase "hold" method, with no "enter" or "exit"
+ * behaviour. Classes that use this legacy function must be leaf
+ * classes that do not chain up to their parent class reset.
+ * There is no mechanism for resetting a device that does not
+ * use the three-phase APIs, so the only place which calls
+ * the legacy_reset hook is do_legacy_reset().
+ */
+ ResettableClass *rc = RESETTABLE_CLASS(dc);
+
+ rc->phases.enter = NULL;
+ rc->phases.hold = do_legacy_reset;
+ rc->phases.exit = NULL;
+ dc->legacy_reset = dev_reset;
}
void device_class_set_parent_realize(DeviceClass *dc,
@@ -873,12 +816,28 @@ Object *qdev_get_machine(void)
static Object *dev;
if (dev == NULL) {
- dev = container_get(object_get_root(), "/machine");
+ dev = object_resolve_path_component(object_get_root(), "machine");
+ /*
+ * Any call to this function before machine is created is treated
+ * as a programming error as of now.
+ */
+ assert(dev);
}
return dev;
}
+Object *machine_get_container(const char *name)
+{
+ Object *container, *machine;
+
+ machine = qdev_get_machine();
+ container = object_resolve_path_component(machine, name);
+ assert(object_dynamic_cast(container, TYPE_CONTAINER));
+
+ return container;
+}
+
char *qdev_get_human_name(DeviceState *dev)
{
g_assert(dev != NULL);
@@ -911,7 +870,7 @@ static const TypeInfo device_type_info = {
.class_init = device_class_init,
.abstract = true,
.class_size = sizeof(DeviceClass),
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_VMSTATE_IF },
{ TYPE_RESETTABLE_INTERFACE },
{ }
diff --git a/hw/core/register.c b/hw/core/register.c
index 95b0150..8f63d9f 100644
--- a/hw/core/register.c
+++ b/hw/core/register.c
@@ -319,7 +319,7 @@ void register_finalize_block(RegisterInfoArray *r_array)
g_free(r_array);
}
-static void register_class_init(ObjectClass *oc, void *data)
+static void register_class_init(ObjectClass *oc, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/core/reset.c b/hw/core/reset.c
index 58dfc8d..65f82fa 100644
--- a/hw/core/reset.c
+++ b/hw/core/reset.c
@@ -24,7 +24,7 @@
*/
#include "qemu/osdep.h"
-#include "sysemu/reset.h"
+#include "system/reset.h"
#include "hw/resettable.h"
#include "hw/core/resetcontainer.h"
@@ -84,7 +84,7 @@ static void legacy_reset_finalize(Object *obj)
{
}
-static void legacy_reset_class_init(ObjectClass *klass, void *data)
+static void legacy_reset_class_init(ObjectClass *klass, const void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
@@ -170,11 +170,8 @@ void qemu_unregister_resettable(Object *obj)
resettable_container_remove(get_root_reset_container(), obj);
}
-void qemu_devices_reset(ShutdownCause reason)
+void qemu_devices_reset(ResetType type)
{
- ResetType type = (reason == SHUTDOWN_CAUSE_SNAPSHOT_LOAD) ?
- RESET_TYPE_SNAPSHOT_LOAD : RESET_TYPE_COLD;
-
/* Reset the simulation */
resettable_reset(OBJECT(get_root_reset_container()), type);
}
diff --git a/hw/core/resetcontainer.c b/hw/core/resetcontainer.c
index e4ece68..5ff1700 100644
--- a/hw/core/resetcontainer.c
+++ b/hw/core/resetcontainer.c
@@ -68,7 +68,8 @@ static void resettable_container_finalize(Object *obj)
{
}
-static void resettable_container_class_init(ObjectClass *klass, void *data)
+static void resettable_container_class_init(ObjectClass *klass,
+ const void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
diff --git a/hw/core/resettable.c b/hw/core/resettable.c
index 6dd3e3d..5cdb4a4 100644
--- a/hw/core/resettable.c
+++ b/hw/core/resettable.c
@@ -93,20 +93,6 @@ static void resettable_child_foreach(ResettableClass *rc, Object *obj,
}
}
-/**
- * resettable_get_tr_func:
- * helper to fetch transitional reset callback if any.
- */
-static ResettableTrFunction resettable_get_tr_func(ResettableClass *rc,
- Object *obj)
-{
- ResettableTrFunction tr_func = NULL;
- if (rc->get_transitional_function) {
- tr_func = rc->get_transitional_function(obj);
- }
- return tr_func;
-}
-
static void resettable_phase_enter(Object *obj, void *opaque, ResetType type)
{
ResettableClass *rc = RESETTABLE_GET_CLASS(obj);
@@ -146,7 +132,7 @@ static void resettable_phase_enter(Object *obj, void *opaque, ResetType type)
if (action_needed) {
trace_resettable_phase_enter_exec(obj, obj_typename, type,
!!rc->phases.enter);
- if (rc->phases.enter && !resettable_get_tr_func(rc, obj)) {
+ if (rc->phases.enter) {
rc->phases.enter(obj, type);
}
s->hold_phase_pending = true;
@@ -171,12 +157,8 @@ static void resettable_phase_hold(Object *obj, void *opaque, ResetType type)
/* exec hold phase */
if (s->hold_phase_pending) {
s->hold_phase_pending = false;
- ResettableTrFunction tr_func = resettable_get_tr_func(rc, obj);
trace_resettable_phase_hold_exec(obj, obj_typename, !!rc->phases.hold);
- if (tr_func) {
- trace_resettable_transitional_function(obj, obj_typename);
- tr_func(obj);
- } else if (rc->phases.hold) {
+ if (rc->phases.hold) {
rc->phases.hold(obj, type);
}
}
@@ -199,7 +181,7 @@ static void resettable_phase_exit(Object *obj, void *opaque, ResetType type)
assert(s->count > 0);
if (--s->count == 0) {
trace_resettable_phase_exit_exec(obj, obj_typename, !!rc->phases.exit);
- if (rc->phases.exit && !resettable_get_tr_func(rc, obj)) {
+ if (rc->phases.exit) {
rc->phases.exit(obj, type);
}
}
diff --git a/hw/core/split-irq.c b/hw/core/split-irq.c
index 3b90af2..f8b4875 100644
--- a/hw/core/split-irq.c
+++ b/hw/core/split-irq.c
@@ -59,12 +59,11 @@ static void split_irq_realize(DeviceState *dev, Error **errp)
qdev_init_gpio_out(dev, s->out_irq, s->num_lines);
}
-static Property split_irq_properties[] = {
+static const Property split_irq_properties[] = {
DEFINE_PROP_UINT16("num-lines", SplitIRQ, num_lines, 1),
- DEFINE_PROP_END_OF_LIST(),
};
-static void split_irq_class_init(ObjectClass *klass, void *data)
+static void split_irq_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/core/sysbus-fdt.c b/hw/core/sysbus-fdt.c
index eebcd28..c339a27 100644
--- a/hw/core/sysbus-fdt.c
+++ b/hw/core/sysbus-fdt.c
@@ -29,13 +29,15 @@
#endif
#include "hw/core/sysbus-fdt.h"
#include "qemu/error-report.h"
-#include "sysemu/device_tree.h"
-#include "sysemu/tpm.h"
+#include "system/device_tree.h"
+#include "system/tpm.h"
#include "hw/platform-bus.h"
#include "hw/vfio/vfio-platform.h"
#include "hw/vfio/vfio-calxeda-xgmac.h"
#include "hw/vfio/vfio-amd-xgbe.h"
+#include "hw/vfio/vfio-region.h"
#include "hw/display/ramfb.h"
+#include "hw/uefi/var-service-api.h"
#include "hw/arm/fdt.h"
/*
@@ -471,6 +473,28 @@ static int add_tpm_tis_fdt_node(SysBusDevice *sbdev, void *opaque)
}
#endif
+static int add_uefi_vars_node(SysBusDevice *sbdev, void *opaque)
+{
+ PlatformBusFDTData *data = opaque;
+ PlatformBusDevice *pbus = data->pbus;
+ const char *parent_node = data->pbus_node_name;
+ void *fdt = data->fdt;
+ uint64_t mmio_base;
+ char *nodename;
+
+ mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, 0);
+ nodename = g_strdup_printf("%s/%s@%" PRIx64, parent_node,
+ UEFI_VARS_FDT_NODE, mmio_base);
+ qemu_fdt_add_subnode(fdt, nodename);
+ qemu_fdt_setprop_string(fdt, nodename,
+ "compatible", UEFI_VARS_FDT_COMPAT);
+ qemu_fdt_setprop_sized_cells(fdt, nodename, "reg",
+ 1, mmio_base,
+ 1, UEFI_VARS_REGS_SIZE);
+ g_free(nodename);
+ return 0;
+}
+
static int no_fdt_node(SysBusDevice *sbdev, void *opaque)
{
return 0;
@@ -495,6 +519,7 @@ static const BindingEntry bindings[] = {
TYPE_BINDING(TYPE_TPM_TIS_SYSBUS, add_tpm_tis_fdt_node),
#endif
TYPE_BINDING(TYPE_RAMFB_DEVICE, no_fdt_node),
+ TYPE_BINDING(TYPE_UEFI_VARS_SYSBUS, add_uefi_vars_node),
TYPE_BINDING("", NULL), /* last element */
};
diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c
index ad34fb7..e71367a 100644
--- a/hw/core/sysbus.c
+++ b/hw/core/sysbus.c
@@ -19,10 +19,9 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "qemu/module.h"
#include "hw/sysbus.h"
#include "monitor/monitor.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent);
static char *sysbus_get_fw_dev_path(DeviceState *dev);
@@ -65,14 +64,14 @@ void foreach_dynamic_sysbus_device(FindSysbusDeviceFunc *func, void *opaque)
};
/* Loop through all sysbus devices that were spawned outside the machine */
- container = container_get(qdev_get_machine(), "/peripheral");
+ container = machine_get_container("peripheral");
find_sysbus_device(container, &find);
- container = container_get(qdev_get_machine(), "/peripheral-anon");
+ container = machine_get_container("peripheral-anon");
find_sysbus_device(container, &find);
}
-static void system_bus_class_init(ObjectClass *klass, void *data)
+static void system_bus_class_init(ObjectClass *klass, const void *data)
{
BusClass *k = BUS_CLASS(klass);
@@ -80,13 +79,6 @@ static void system_bus_class_init(ObjectClass *klass, void *data)
k->get_fw_dev_path = sysbus_get_fw_dev_path;
}
-static const TypeInfo system_bus_info = {
- .name = TYPE_SYSTEM_BUS,
- .parent = TYPE_BUS,
- .instance_size = sizeof(BusState),
- .class_init = system_bus_class_init,
-};
-
/* Check whether an IRQ source exists */
bool sysbus_has_irq(SysBusDevice *dev, int n)
{
@@ -154,16 +146,6 @@ static void sysbus_mmio_map_common(SysBusDevice *dev, int n, hwaddr addr,
}
}
-void sysbus_mmio_unmap(SysBusDevice *dev, int n)
-{
- assert(n >= 0 && n < dev->num_mmio);
-
- if (dev->mmio[n].addr != (hwaddr)-1) {
- memory_region_del_subregion(get_system_memory(), dev->mmio[n].memory);
- dev->mmio[n].addr = (hwaddr)-1;
- }
-}
-
void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr)
{
sysbus_mmio_map_common(dev, n, addr, false, 0);
@@ -298,7 +280,7 @@ static char *sysbus_get_fw_dev_path(DeviceState *dev)
return g_strdup(qdev_fw_name(dev));
}
-static void sysbus_device_class_init(ObjectClass *klass, void *data)
+static void sysbus_device_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
k->realize = sysbus_device_realize;
@@ -316,15 +298,6 @@ static void sysbus_device_class_init(ObjectClass *klass, void *data)
k->user_creatable = false;
}
-static const TypeInfo sysbus_device_type_info = {
- .name = TYPE_SYS_BUS_DEVICE,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(SysBusDevice),
- .abstract = true,
- .class_size = sizeof(SysBusDeviceClass),
- .class_init = sysbus_device_class_init,
-};
-
static BusState *main_system_bus;
static void main_system_bus_create(void)
@@ -333,8 +306,8 @@ static void main_system_bus_create(void)
* assign main_system_bus before qbus_init()
* in order to make "if (bus != sysbus_get_default())" work
*/
- main_system_bus = g_malloc0(system_bus_info.instance_size);
- qbus_init(main_system_bus, system_bus_info.instance_size,
+ main_system_bus = g_new0(BusState, 1);
+ qbus_init(main_system_bus, sizeof(BusState),
TYPE_SYSTEM_BUS, NULL, "main-system-bus");
OBJECT(main_system_bus)->free = g_free;
}
@@ -347,10 +320,36 @@ BusState *sysbus_get_default(void)
return main_system_bus;
}
-static void sysbus_register_types(void)
+static void dynamic_sysbus_device_class_init(ObjectClass *klass,
+ const void *data)
{
- type_register_static(&system_bus_info);
- type_register_static(&sysbus_device_type_info);
+ DeviceClass *k = DEVICE_CLASS(klass);
+
+ k->user_creatable = true;
+ k->hotpluggable = false;
}
-type_init(sysbus_register_types)
+static const TypeInfo sysbus_types[] = {
+ {
+ .name = TYPE_SYSTEM_BUS,
+ .parent = TYPE_BUS,
+ .instance_size = sizeof(BusState),
+ .class_init = system_bus_class_init,
+ },
+ {
+ .name = TYPE_SYS_BUS_DEVICE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(SysBusDevice),
+ .abstract = true,
+ .class_size = sizeof(SysBusDeviceClass),
+ .class_init = sysbus_device_class_init,
+ },
+ {
+ .name = TYPE_DYNAMIC_SYS_BUS_DEVICE,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .class_init = dynamic_sysbus_device_class_init,
+ .abstract = true,
+ }
+};
+
+DEFINE_TYPES(sysbus_types)
diff --git a/hw/core/uboot_image.h b/hw/core/uboot_image.h
index 18ac293..e4dcfb0 100644
--- a/hw/core/uboot_image.h
+++ b/hw/core/uboot_image.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* (C) Copyright 2008 Semihalf
*
diff --git a/hw/core/vm-change-state-handler.c b/hw/core/vm-change-state-handler.c
index 8e26392..99c642b 100644
--- a/hw/core/vm-change-state-handler.c
+++ b/hw/core/vm-change-state-handler.c
@@ -17,7 +17,7 @@
#include "qemu/osdep.h"
#include "hw/qdev-core.h"
-#include "sysemu/runstate.h"
+#include "system/runstate.h"
static int qdev_get_dev_tree_depth(DeviceState *dev)
{
@@ -40,6 +40,7 @@ static int qdev_get_dev_tree_depth(DeviceState *dev)
* qdev_add_vm_change_state_handler:
* @dev: the device that owns this handler
* @cb: the callback function to be invoked
+ * @cb_ret: the callback function with return value to be invoked
* @opaque: user data passed to the callback function
*
* This function works like qemu_add_vm_change_state_handler() except callbacks
@@ -50,25 +51,30 @@ static int qdev_get_dev_tree_depth(DeviceState *dev)
* controller's callback is invoked before the children on its bus when the VM
* starts running. The order is reversed when the VM stops running.
*
+ * Note that the parameter `cb` and `cb_ret` are mutually exclusive.
+ *
* Returns: an entry to be freed with qemu_del_vm_change_state_handler()
*/
VMChangeStateEntry *qdev_add_vm_change_state_handler(DeviceState *dev,
VMChangeStateHandler *cb,
+ VMChangeStateHandlerWithRet *cb_ret,
void *opaque)
{
- return qdev_add_vm_change_state_handler_full(dev, cb, NULL, opaque);
+ assert(!cb || !cb_ret);
+ return qdev_add_vm_change_state_handler_full(dev, cb, NULL, cb_ret, opaque);
}
/*
* Exactly like qdev_add_vm_change_state_handler() but passes a prepare_cb
- * argument too.
+ * and the cb_ret arguments too.
*/
VMChangeStateEntry *qdev_add_vm_change_state_handler_full(
- DeviceState *dev, VMChangeStateHandler *cb,
- VMChangeStateHandler *prepare_cb, void *opaque)
+ DeviceState *dev, VMChangeStateHandler *cb, VMChangeStateHandler *prepare_cb,
+ VMChangeStateHandlerWithRet *cb_ret, void *opaque)
{
int depth = qdev_get_dev_tree_depth(dev);
- return qemu_add_vm_change_state_handler_prio_full(cb, prepare_cb, opaque,
- depth);
+ assert(!cb || !cb_ret);
+ return qemu_add_vm_change_state_handler_prio_full(cb, prepare_cb, cb_ret,
+ opaque, depth);
}