summaryrefslogtreecommitdiffstats
path: root/hw/core/machine.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/core/machine.c')
-rw-r--r--hw/core/machine.c241
1 files changed, 215 insertions, 26 deletions
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 700c1e76b8..3264c1e11d 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -21,12 +21,14 @@
#include "qapi/qapi-visit-common.h"
#include "qapi/qapi-visit-machine.h"
#include "qapi/visitor.h"
+#include "qom/object_interfaces.h"
#include "hw/sysbus.h"
#include "sysemu/cpus.h"
#include "sysemu/sysemu.h"
#include "sysemu/reset.h"
#include "sysemu/runstate.h"
#include "sysemu/numa.h"
+#include "sysemu/xen.h"
#include "qemu/error-report.h"
#include "sysemu/qtest.h"
#include "hw/pci/pci.h"
@@ -36,6 +38,7 @@
#include "exec/confidential-guest-support.h"
#include "hw/virtio/virtio.h"
#include "hw/virtio/virtio-pci.h"
+#include "qom/object_interfaces.h"
GlobalProperty hw_compat_7_0[] = {};
const size_t hw_compat_7_0_len = G_N_ELEMENTS(hw_compat_7_0);
@@ -523,6 +526,78 @@ static void machine_set_hmat(Object *obj, bool value, Error **errp)
ms->numa_state->hmat_enabled = value;
}
+static void machine_get_mem(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+ MemorySizeConfiguration mem = {
+ .has_size = true,
+ .size = ms->ram_size,
+ .has_max_size = !!ms->ram_slots,
+ .max_size = ms->maxram_size,
+ .has_slots = !!ms->ram_slots,
+ .slots = ms->ram_slots,
+ };
+ MemorySizeConfiguration *p_mem = &mem;
+
+ visit_type_MemorySizeConfiguration(v, name, &p_mem, &error_abort);
+}
+
+static void machine_set_mem(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+ MachineClass *mc = MACHINE_GET_CLASS(obj);
+ MemorySizeConfiguration *mem;
+
+ ERRP_GUARD();
+
+ if (!visit_type_MemorySizeConfiguration(v, name, &mem, errp)) {
+ return;
+ }
+
+ if (!mem->has_size) {
+ mem->has_size = true;
+ mem->size = mc->default_ram_size;
+ }
+ mem->size = QEMU_ALIGN_UP(mem->size, 8192);
+ if (mc->fixup_ram_size) {
+ mem->size = mc->fixup_ram_size(mem->size);
+ }
+ if ((ram_addr_t)mem->size != mem->size) {
+ error_setg(errp, "ram size too large");
+ goto out_free;
+ }
+
+ if (mem->has_max_size) {
+ if (mem->max_size < mem->size) {
+ error_setg(errp, "invalid value of maxmem: "
+ "maximum memory size (0x%" PRIx64 ") must be at least "
+ "the initial memory size (0x%" PRIx64 ")",
+ mem->max_size, mem->size);
+ goto out_free;
+ }
+ if (mem->has_slots && mem->slots && mem->max_size == mem->size) {
+ error_setg(errp, "invalid value of maxmem: "
+ "memory slots were specified but maximum memory size "
+ "(0x%" PRIx64 ") is equal to the initial memory size "
+ "(0x%" PRIx64 ")", mem->max_size, mem->size);
+ goto out_free;
+ }
+ ms->maxram_size = mem->max_size;
+ } else {
+ if (mem->has_slots) {
+ error_setg(errp, "slots specified but no max-size");
+ goto out_free;
+ }
+ ms->maxram_size = mem->size;
+ }
+ ms->ram_size = mem->size;
+ ms->ram_slots = mem->has_slots ? mem->slots : 0;
+out_free:
+ qapi_free_MemorySizeConfiguration(mem);
+}
+
static char *machine_get_nvdimm_persistence(Object *obj, Error **errp)
{
MachineState *ms = MACHINE(obj);
@@ -581,21 +656,6 @@ bool device_type_is_dynamic_sysbus(MachineClass *mc, const char *type)
return allowed;
}
-static char *machine_get_memdev(Object *obj, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- return g_strdup(ms->ram_memdev_id);
-}
-
-static void machine_set_memdev(Object *obj, const char *value, Error **errp)
-{
- MachineState *ms = MACHINE(obj);
-
- g_free(ms->ram_memdev_id);
- ms->ram_memdev_id = g_strdup(value);
-}
-
HotpluggableCPUList *machine_query_hotpluggable_cpus(MachineState *machine)
{
int i;
@@ -784,6 +844,65 @@ static void machine_set_smp(Object *obj, Visitor *v, const char *name,
machine_parse_smp_config(ms, config, errp);
}
+static void machine_get_boot(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+ BootConfiguration *config = &ms->boot_config;
+ visit_type_BootConfiguration(v, name, &config, &error_abort);
+}
+
+static void machine_free_boot_config(MachineState *ms)
+{
+ g_free(ms->boot_config.order);
+ g_free(ms->boot_config.once);
+ g_free(ms->boot_config.splash);
+}
+
+static void machine_copy_boot_config(MachineState *ms, BootConfiguration *config)
+{
+ MachineClass *machine_class = MACHINE_GET_CLASS(ms);
+
+ machine_free_boot_config(ms);
+ ms->boot_config = *config;
+ if (!config->has_order) {
+ ms->boot_config.has_order = true;
+ ms->boot_config.order = g_strdup(machine_class->default_boot_order);
+ }
+}
+
+static void machine_set_boot(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ ERRP_GUARD();
+ MachineState *ms = MACHINE(obj);
+ BootConfiguration *config = NULL;
+
+ if (!visit_type_BootConfiguration(v, name, &config, errp)) {
+ return;
+ }
+ if (config->has_order) {
+ validate_bootdevices(config->order, errp);
+ if (*errp) {
+ goto out_free;
+ }
+ }
+ if (config->has_once) {
+ validate_bootdevices(config->once, errp);
+ if (*errp) {
+ goto out_free;
+ }
+ }
+
+ machine_copy_boot_config(ms, config);
+ /* Strings live in ms->boot_config. */
+ free(config);
+ return;
+
+out_free:
+ qapi_free_BootConfiguration(config);
+}
+
static void machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -822,6 +941,12 @@ static void machine_class_init(ObjectClass *oc, void *data)
object_class_property_set_description(oc, "dumpdtb",
"Dump current dtb to a file and quit");
+ object_class_property_add(oc, "boot", "BootConfiguration",
+ machine_get_boot, machine_set_boot,
+ NULL, NULL);
+ object_class_property_set_description(oc, "boot",
+ "Boot configuration");
+
object_class_property_add(oc, "smp", "SMPConfiguration",
machine_get_smp, machine_set_smp,
NULL, NULL);
@@ -883,11 +1008,18 @@ static void machine_class_init(ObjectClass *oc, void *data)
object_class_property_set_description(oc, "memory-encryption",
"Set memory encryption object to use");
- object_class_property_add_str(oc, "memory-backend",
- machine_get_memdev, machine_set_memdev);
+ object_class_property_add_link(oc, "memory-backend", TYPE_MEMORY_BACKEND,
+ offsetof(MachineState, memdev), object_property_allow_set_link,
+ OBJ_PROP_LINK_STRONG);
object_class_property_set_description(oc, "memory-backend",
"Set RAM backend"
"Valid value is ID of hostmem based backend");
+
+ object_class_property_add(oc, "memory", "MemorySizeConfiguration",
+ machine_get_mem, machine_set_mem,
+ NULL, NULL);
+ object_class_property_set_description(oc, "memory",
+ "Memory size configuration");
}
static void machine_class_base_init(ObjectClass *oc, void *data)
@@ -918,6 +1050,8 @@ static void machine_initfn(Object *obj)
ms->mem_merge = true;
ms->enable_graphics = true;
ms->kernel_cmdline = g_strdup("");
+ ms->ram_size = mc->default_ram_size;
+ ms->maxram_size = mc->default_ram_size;
if (mc->nvdimm_supported) {
Object *obj = OBJECT(ms);
@@ -955,12 +1089,15 @@ static void machine_initfn(Object *obj)
ms->smp.clusters = 1;
ms->smp.cores = 1;
ms->smp.threads = 1;
+
+ machine_copy_boot_config(ms, &(BootConfiguration){ 0 });
}
static void machine_finalize(Object *obj)
{
MachineState *ms = MACHINE(obj);
+ machine_free_boot_config(ms);
g_free(ms->kernel_filename);
g_free(ms->initrd_filename);
g_free(ms->kernel_cmdline);
@@ -1122,7 +1259,40 @@ MemoryRegion *machine_consume_memdev(MachineState *machine,
return ret;
}
-void machine_run_board_init(MachineState *machine)
+static bool create_default_memdev(MachineState *ms, const char *path, Error **errp)
+{
+ Object *obj;
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+ bool r = false;
+
+ obj = object_new(path ? TYPE_MEMORY_BACKEND_FILE : TYPE_MEMORY_BACKEND_RAM);
+ if (path) {
+ if (!object_property_set_str(obj, "mem-path", path, errp)) {
+ goto out;
+ }
+ }
+ if (!object_property_set_int(obj, "size", ms->ram_size, errp)) {
+ goto out;
+ }
+ object_property_add_child(object_get_objects_root(), mc->default_ram_id,
+ obj);
+ /* Ensure backend's memory region name is equal to mc->default_ram_id */
+ if (!object_property_set_bool(obj, "x-use-canonical-path-for-ramblock-id",
+ false, errp)) {
+ goto out;
+ }
+ if (!user_creatable_complete(USER_CREATABLE(obj), errp)) {
+ goto out;
+ }
+ r = object_property_set_link(OBJECT(ms), "memory-backend", obj, errp);
+
+out:
+ object_unref(obj);
+ return r;
+}
+
+
+void machine_run_board_init(MachineState *machine, const char *mem_path, Error **errp)
{
MachineClass *machine_class = MACHINE_GET_CLASS(machine);
ObjectClass *oc = object_class_by_name(machine->cpu_type);
@@ -1133,11 +1303,26 @@ void machine_run_board_init(MachineState *machine)
clock values from the log. */
replay_checkpoint(CHECKPOINT_INIT);
- if (machine->ram_memdev_id) {
- Object *o;
- o = object_resolve_path_type(machine->ram_memdev_id,
- TYPE_MEMORY_BACKEND, NULL);
- machine->ram = machine_consume_memdev(machine, MEMORY_BACKEND(o));
+ if (!xen_enabled()) {
+ /* On 32-bit hosts, QEMU is limited by virtual address space */
+ if (machine->ram_size > (2047 << 20) && HOST_LONG_BITS == 32) {
+ error_setg(errp, "at most 2047 MB RAM can be simulated");
+ return;
+ }
+ }
+
+ if (machine->memdev) {
+ ram_addr_t backend_size = object_property_get_uint(OBJECT(machine->memdev),
+ "size", &error_abort);
+ if (backend_size != machine->ram_size) {
+ error_setg(errp, "Machine memory size does not match the size of the memory backend");
+ return;
+ }
+ } else if (machine_class->default_ram_id && machine->ram_size &&
+ numa_uses_legacy_mem()) {
+ if (!create_default_memdev(current_machine, mem_path, errp)) {
+ return;
+ }
}
if (machine->numa_state) {
@@ -1147,6 +1332,10 @@ void machine_run_board_init(MachineState *machine)
}
}
+ if (!machine->ram && machine->memdev) {
+ machine->ram = machine_consume_memdev(machine, machine->memdev);
+ }
+
/* If the machine supports the valid_cpu_types check and the user
* specified a CPU with -cpu check here that the user CPU is supported.
*/
@@ -1229,9 +1418,9 @@ void qdev_machine_creation_done(void)
{
cpu_synchronize_all_post_init();
- if (current_machine->boot_once) {
- qemu_boot_set(current_machine->boot_once, &error_fatal);
- qemu_register_reset(restore_boot_order, g_strdup(current_machine->boot_order));
+ if (current_machine->boot_config.has_once) {
+ qemu_boot_set(current_machine->boot_config.once, &error_fatal);
+ qemu_register_reset(restore_boot_order, g_strdup(current_machine->boot_config.order));
}
/*