/* * Virtual Machine coreinfo device * * Copyright (C) 2017 Red Hat, Inc. * * Authors: Marc-André Lureau * * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. * */ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/module.h" #include "sysemu/reset.h" #include "hw/nvram/fw_cfg.h" #include "migration/vmstate.h" #include "hw/misc/vmcoreinfo.h" static void fw_cfg_vmci_write(void *dev, off_t offset, size_t len) { VMCoreInfoState *s = VMCOREINFO(dev); s->has_vmcoreinfo = offset == 0 && len == sizeof(s->vmcoreinfo) && s->vmcoreinfo.guest_format != FW_CFG_VMCOREINFO_FORMAT_NONE; } static void vmcoreinfo_reset(void *dev) { VMCoreInfoState *s = VMCOREINFO(dev); s->has_vmcoreinfo = false; memset(&s->vmcoreinfo, 0, sizeof(s->vmcoreinfo)); s->vmcoreinfo.host_format = cpu_to_le16(FW_CFG_VMCOREINFO_FORMAT_ELF); } static void vmcoreinfo_realize(DeviceState *dev, Error **errp) { VMCoreInfoState *s = VMCOREINFO(dev); FWCfgState *fw_cfg = fw_cfg_find(); /* for gdb script dump-guest-memory.py */ static VMCoreInfoState * volatile vmcoreinfo_state G_GNUC_UNUSED; /* Given that this function is executing, there is at least one VMCOREINFO * device. Check if there are several. */ if (!vmcoreinfo_find()) { error_setg(errp, "at most one %s device is permitted", VMCOREINFO_DEVICE); return; } if (!fw_cfg || !fw_cfg->dma_enabled) { error_setg(errp, "%s device requires fw_cfg with DMA", VMCOREINFO_DEVICE); return; } fw_cfg_add_file_callback(fw_cfg, FW_CFG_VMCOREINFO_FILENAME, NULL, fw_cfg_vmci_write, s, &s->vmcoreinfo, sizeof(s->vmcoreinfo), false); /* * This device requires to register a global reset because it is * not plugged to a bus (which, as its QOM parent, would reset it). */ qemu_register_reset(vmcoreinfo_reset, dev); vmcoreinfo_state = s; } static const VMStateDescription vmstate_vmcoreinfo = { .name = "vmcoreinfo", .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { VMSTATE_BOOL(has_vmcoreinfo, VMCoreInfoState), VMSTATE_UINT16(vmcoreinfo.host_format, VMCoreInfoState), VMSTATE_UINT16(vmcoreinfo.guest_format, VMCoreInfoState), VMSTATE_UINT32(vmcoreinfo.size, VMCoreInfoState), VMSTATE_UINT64(vmcoreinfo.paddr, VMCoreInfoState), VMSTATE_END_OF_LIST() }, }; static void vmcoreinfo_device_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->vmsd = &vmstate_vmcoreinfo; dc->realize = vmcoreinfo_realize; dc->hotpluggable = false; set_bit(DEVICE_CATEGORY_MISC, dc->categories); } static const TypeInfo vmcoreinfo_device_info = { .name = VMCOREINFO_DEVICE, .parent = TYPE_DEVICE, .instance_size = sizeof(VMCoreInfoState), .class_init = vmcoreinfo_device_class_init, }; static void vmcoreinfo_register_types(void) { type_register_static(&vmcoreinfo_device_info); } type_init(vmcoreinfo_register_types)