*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
+#include "qemu/datadir.h"
#include "sysemu/sysemu.h"
#include "sysemu/dma.h"
#include "sysemu/reset.h"
#include "qemu/config-file.h"
#include "qemu/cutils.h"
#include "qapi/error.h"
+#include "hw/acpi/aml-build.h"
+#include "hw/pci/pci_bus.h"
#define FW_CFG_FILE_SLOTS_DFLT 0x20
dma_addr = s->dma_addr;
s->dma_addr = 0;
- if (dma_memory_read(s->dma_as, dma_addr, &dma, sizeof(dma))) {
+ if (dma_memory_read(s->dma_as, dma_addr,
+ &dma, sizeof(dma), MEMTXATTRS_UNSPECIFIED)) {
stl_be_dma(s->dma_as, dma_addr + offsetof(FWCfgDmaAccess, control),
- FW_CFG_DMA_CTL_ERROR);
+ FW_CFG_DMA_CTL_ERROR, MEMTXATTRS_UNSPECIFIED);
return;
}
* tested before.
*/
if (read) {
- if (dma_memory_set(s->dma_as, dma.address, 0, len)) {
+ if (dma_memory_set(s->dma_as, dma.address, 0, len,
+ MEMTXATTRS_UNSPECIFIED)) {
dma.control |= FW_CFG_DMA_CTL_ERROR;
}
}
*/
if (read) {
if (dma_memory_write(s->dma_as, dma.address,
- &e->data[s->cur_offset], len)) {
+ &e->data[s->cur_offset], len,
+ MEMTXATTRS_UNSPECIFIED)) {
dma.control |= FW_CFG_DMA_CTL_ERROR;
}
}
if (!e->allow_write ||
len != dma.length ||
dma_memory_read(s->dma_as, dma.address,
- &e->data[s->cur_offset], len)) {
+ &e->data[s->cur_offset], len,
+ MEMTXATTRS_UNSPECIFIED)) {
dma.control |= FW_CFG_DMA_CTL_ERROR;
} else if (e->write_cb) {
e->write_cb(e->callback_opaque, s->cur_offset, len);
}
stl_be_dma(s->dma_as, dma_addr + offsetof(FWCfgDmaAccess, control),
- dma.control);
+ dma.control, MEMTXATTRS_UNSPECIFIED);
trace_fw_cfg_read(s, 0);
}
}
static int put_unused(QEMUFile *f, void *pv, size_t size,
- const VMStateField *field, QJSON *vmdesc)
+ const VMStateField *field, JSONWriter *vmdesc)
{
fprintf(stderr, "uint32_as_uint16 is only used for backward compatibility.\n");
fprintf(stderr, "This functions shouldn't be called.\n");
return s->dma_enabled;
}
+static bool fw_cfg_acpi_mr_restore(void *opaque)
+{
+ FWCfgState *s = opaque;
+ bool mr_aligned;
+
+ mr_aligned = QEMU_IS_ALIGNED(s->table_mr_size, qemu_real_host_page_size()) &&
+ QEMU_IS_ALIGNED(s->linker_mr_size, qemu_real_host_page_size()) &&
+ QEMU_IS_ALIGNED(s->rsdp_mr_size, qemu_real_host_page_size());
+ return s->acpi_mr_restore && !mr_aligned;
+}
+
+static void fw_cfg_update_mr(FWCfgState *s, uint16_t key, size_t size)
+{
+ MemoryRegion *mr;
+ ram_addr_t offset;
+ int arch = !!(key & FW_CFG_ARCH_LOCAL);
+ void *ptr;
+
+ key &= FW_CFG_ENTRY_MASK;
+ assert(key < fw_cfg_max_entry(s));
+
+ ptr = s->entries[arch][key].data;
+ mr = memory_region_from_host(ptr, &offset);
+
+ memory_region_ram_resize(mr, size, &error_abort);
+}
+
+static int fw_cfg_acpi_mr_restore_post_load(void *opaque, int version_id)
+{
+ FWCfgState *s = opaque;
+ int i, index;
+
+ assert(s->files);
+
+ index = be32_to_cpu(s->files->count);
+
+ for (i = 0; i < index; i++) {
+ if (!strcmp(s->files->f[i].name, ACPI_BUILD_TABLE_FILE)) {
+ fw_cfg_update_mr(s, FW_CFG_FILE_FIRST + i, s->table_mr_size);
+ } else if (!strcmp(s->files->f[i].name, ACPI_BUILD_LOADER_FILE)) {
+ fw_cfg_update_mr(s, FW_CFG_FILE_FIRST + i, s->linker_mr_size);
+ } else if (!strcmp(s->files->f[i].name, ACPI_BUILD_RSDP_FILE)) {
+ fw_cfg_update_mr(s, FW_CFG_FILE_FIRST + i, s->rsdp_mr_size);
+ }
+ }
+
+ return 0;
+}
+
static const VMStateDescription vmstate_fw_cfg_dma = {
.name = "fw_cfg/dma",
.needed = fw_cfg_dma_enabled,
},
};
+static const VMStateDescription vmstate_fw_cfg_acpi_mr = {
+ .name = "fw_cfg/acpi_mr",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = fw_cfg_acpi_mr_restore,
+ .post_load = fw_cfg_acpi_mr_restore_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT64(table_mr_size, FWCfgState),
+ VMSTATE_UINT64(linker_mr_size, FWCfgState),
+ VMSTATE_UINT64(rsdp_mr_size, FWCfgState),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
static const VMStateDescription vmstate_fw_cfg = {
.name = "fw_cfg",
.version_id = 2,
},
.subsections = (const VMStateDescription*[]) {
&vmstate_fw_cfg_dma,
+ &vmstate_fw_cfg_acpi_mr,
NULL,
}
};
{ "etc/tpm/log", 150 },
{ "etc/acpi/rsdp", 160 },
{ "bootorder", 170 },
+ { "etc/msr_feature_control", 180 },
#define FW_CFG_ORDER_OVERRIDE_LAST 200
};
+/*
+ * Any sub-page size update to these table MRs will be lost during migration,
+ * as we use aligned size in ram_load_precopy() -> qemu_ram_resize() path.
+ * In order to avoid the inconsistency in sizes save them seperately and
+ * migrate over in vmstate post_load().
+ */
+static void fw_cfg_acpi_mr_save(FWCfgState *s, const char *filename, size_t len)
+{
+ if (!strcmp(filename, ACPI_BUILD_TABLE_FILE)) {
+ s->table_mr_size = len;
+ } else if (!strcmp(filename, ACPI_BUILD_LOADER_FILE)) {
+ s->linker_mr_size = len;
+ } else if (!strcmp(filename, ACPI_BUILD_RSDP_FILE)) {
+ s->rsdp_mr_size = len;
+ }
+}
+
static int get_fw_cfg_order(FWCfgState *s, const char *name)
{
int i;
trace_fw_cfg_add_file(s, index, s->files->f[index].name, len);
s->files->count = cpu_to_be32(count+1);
+ fw_cfg_acpi_mr_save(s, filename, len);
}
void fw_cfg_add_file(FWCfgState *s, const char *filename,
ptr = fw_cfg_modify_bytes_read(s, FW_CFG_FILE_FIRST + i,
data, len);
s->files->f[i].size = cpu_to_be32(len);
+ fw_cfg_acpi_mr_save(s, filename, len);
return ptr;
}
}
return NULL;
}
+bool fw_cfg_add_from_generator(FWCfgState *s, const char *filename,
+ const char *gen_id, Error **errp)
+{
+ FWCfgDataGeneratorClass *klass;
+ GByteArray *array;
+ Object *obj;
+ gsize size;
+
+ obj = object_resolve_path_component(object_get_objects_root(), gen_id);
+ if (!obj) {
+ error_setg(errp, "Cannot find object ID '%s'", gen_id);
+ return false;
+ }
+ if (!object_dynamic_cast(obj, TYPE_FW_CFG_DATA_GENERATOR_INTERFACE)) {
+ error_setg(errp, "Object ID '%s' is not a '%s' subclass",
+ gen_id, TYPE_FW_CFG_DATA_GENERATOR_INTERFACE);
+ return false;
+ }
+ klass = FW_CFG_DATA_GENERATOR_GET_CLASS(obj);
+ array = klass->get_data(obj, errp);
+ if (!array) {
+ return false;
+ }
+ size = array->len;
+ fw_cfg_add_file(s, filename, g_byte_array_free(array, FALSE), size);
+
+ return true;
+}
+
+void fw_cfg_add_extra_pci_roots(PCIBus *bus, FWCfgState *s)
+{
+ int extra_hosts = 0;
+
+ if (!bus) {
+ return;
+ }
+
+ QLIST_FOREACH(bus, &bus->child, sibling) {
+ /* look for expander root buses */
+ if (pci_bus_is_root(bus)) {
+ extra_hosts++;
+ }
+ }
+
+ if (extra_hosts && s) {
+ uint64_t *val = g_malloc(sizeof(*val));
+ *val = cpu_to_le64(extra_hosts);
+ fw_cfg_add_file(s, "etc/extra-pci-roots", val, sizeof(*val));
+ }
+}
+
static void fw_cfg_machine_reset(void *opaque)
{
MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
qemu_register_reset(fw_cfg_machine_reset, s);
}
-
+static Property fw_cfg_properties[] = {
+ DEFINE_PROP_BOOL("acpi-mr-restore", FWCfgState, acpi_mr_restore, true),
+ DEFINE_PROP_END_OF_LIST(),
+};
static void fw_cfg_common_realize(DeviceState *dev, Error **errp)
{
FWCfgState *s;
bool dma_requested = dma_iobase && dma_as;
- dev = qdev_create(NULL, TYPE_FW_CFG_IO);
+ dev = qdev_new(TYPE_FW_CFG_IO);
if (!dma_requested) {
qdev_prop_set_bit(dev, "dma_enabled", false);
}
object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG,
- OBJECT(dev), NULL);
- qdev_init_nofail(dev);
+ OBJECT(dev));
sbd = SYS_BUS_DEVICE(dev);
+ sysbus_realize_and_unref(sbd, &error_fatal);
ios = FW_CFG_IO(dev);
sysbus_add_io(sbd, iobase, &ios->comb_iomem);
FWCfgState *s;
bool dma_requested = dma_addr && dma_as;
- dev = qdev_create(NULL, TYPE_FW_CFG_MEM);
+ dev = qdev_new(TYPE_FW_CFG_MEM);
qdev_prop_set_uint32(dev, "data_width", data_width);
if (!dma_requested) {
qdev_prop_set_bit(dev, "dma_enabled", false);
}
object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG,
- OBJECT(dev), NULL);
- qdev_init_nofail(dev);
+ OBJECT(dev));
sbd = SYS_BUS_DEVICE(dev);
+ sysbus_realize_and_unref(sbd, &error_fatal);
sysbus_mmio_map(sbd, 0, ctl_addr);
sysbus_mmio_map(sbd, 1, data_addr);
dc->reset = fw_cfg_reset;
dc->vmsd = &vmstate_fw_cfg;
+
+ device_class_set_props(dc, fw_cfg_properties);
}
static const TypeInfo fw_cfg_info = {
static void fw_cfg_io_realize(DeviceState *dev, Error **errp)
{
+ ERRP_GUARD();
FWCfgIoState *s = FW_CFG_IO(dev);
- Error *local_err = NULL;
- fw_cfg_file_slots_allocate(FW_CFG(s), &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
+ fw_cfg_file_slots_allocate(FW_CFG(s), errp);
+ if (*errp) {
return;
}
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = fw_cfg_io_realize;
- dc->props = fw_cfg_io_properties;
+ device_class_set_props(dc, fw_cfg_io_properties);
}
static const TypeInfo fw_cfg_io_info = {
static void fw_cfg_mem_realize(DeviceState *dev, Error **errp)
{
+ ERRP_GUARD();
FWCfgMemState *s = FW_CFG_MEM(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
const MemoryRegionOps *data_ops = &fw_cfg_data_mem_ops;
- Error *local_err = NULL;
- fw_cfg_file_slots_allocate(FW_CFG(s), &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
+ fw_cfg_file_slots_allocate(FW_CFG(s), errp);
+ if (*errp) {
return;
}
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = fw_cfg_mem_realize;
- dc->props = fw_cfg_mem_properties;
+ device_class_set_props(dc, fw_cfg_mem_properties);
}
static const TypeInfo fw_cfg_mem_info = {
.class_init = fw_cfg_mem_class_init,
};
-
static void fw_cfg_register_types(void)
{
type_register_static(&fw_cfg_info);