xref: /openbmc/qemu/hw/misc/vmcoreinfo.c (revision 0b8fa32f551e863bb548a11394239239270dd3dc)
16e43353fSMarc-André Lureau /*
26e43353fSMarc-André Lureau  * Virtual Machine coreinfo device
36e43353fSMarc-André Lureau  *
46e43353fSMarc-André Lureau  * Copyright (C) 2017 Red Hat, Inc.
56e43353fSMarc-André Lureau  *
66e43353fSMarc-André Lureau  * Authors: Marc-André Lureau <marcandre.lureau@redhat.com>
76e43353fSMarc-André Lureau  *
86e43353fSMarc-André Lureau  * This work is licensed under the terms of the GNU GPL, version 2 or later.
96e43353fSMarc-André Lureau  * See the COPYING file in the top-level directory.
106e43353fSMarc-André Lureau  *
116e43353fSMarc-André Lureau  */
12*0b8fa32fSMarkus Armbruster 
136e43353fSMarc-André Lureau #include "qemu/osdep.h"
146e43353fSMarc-André Lureau #include "qapi/error.h"
15*0b8fa32fSMarkus Armbruster #include "qemu/module.h"
166e43353fSMarc-André Lureau #include "hw/nvram/fw_cfg.h"
176e43353fSMarc-André Lureau #include "hw/misc/vmcoreinfo.h"
186e43353fSMarc-André Lureau 
196e43353fSMarc-André Lureau static void fw_cfg_vmci_write(void *dev, off_t offset, size_t len)
206e43353fSMarc-André Lureau {
216e43353fSMarc-André Lureau     VMCoreInfoState *s = VMCOREINFO(dev);
226e43353fSMarc-André Lureau 
236e43353fSMarc-André Lureau     s->has_vmcoreinfo = offset == 0 && len == sizeof(s->vmcoreinfo)
245be5df72SMarc-André Lureau         && s->vmcoreinfo.guest_format != FW_CFG_VMCOREINFO_FORMAT_NONE;
256e43353fSMarc-André Lureau }
266e43353fSMarc-André Lureau 
276e43353fSMarc-André Lureau static void vmcoreinfo_reset(void *dev)
286e43353fSMarc-André Lureau {
296e43353fSMarc-André Lureau     VMCoreInfoState *s = VMCOREINFO(dev);
306e43353fSMarc-André Lureau 
316e43353fSMarc-André Lureau     s->has_vmcoreinfo = false;
326e43353fSMarc-André Lureau     memset(&s->vmcoreinfo, 0, sizeof(s->vmcoreinfo));
335be5df72SMarc-André Lureau     s->vmcoreinfo.host_format = cpu_to_le16(FW_CFG_VMCOREINFO_FORMAT_ELF);
346e43353fSMarc-André Lureau }
356e43353fSMarc-André Lureau 
366e43353fSMarc-André Lureau static void vmcoreinfo_realize(DeviceState *dev, Error **errp)
376e43353fSMarc-André Lureau {
386e43353fSMarc-André Lureau     VMCoreInfoState *s = VMCOREINFO(dev);
396e43353fSMarc-André Lureau     FWCfgState *fw_cfg = fw_cfg_find();
40c3b1642bSMarc-André Lureau     /* for gdb script dump-guest-memory.py */
41c3b1642bSMarc-André Lureau     static VMCoreInfoState * volatile vmcoreinfo_state G_GNUC_UNUSED;
426e43353fSMarc-André Lureau 
436e43353fSMarc-André Lureau     /* Given that this function is executing, there is at least one VMCOREINFO
446e43353fSMarc-André Lureau      * device. Check if there are several.
456e43353fSMarc-André Lureau      */
466e43353fSMarc-André Lureau     if (!vmcoreinfo_find()) {
476e43353fSMarc-André Lureau         error_setg(errp, "at most one %s device is permitted",
486e43353fSMarc-André Lureau                    VMCOREINFO_DEVICE);
496e43353fSMarc-André Lureau         return;
506e43353fSMarc-André Lureau     }
516e43353fSMarc-André Lureau 
526e43353fSMarc-André Lureau     if (!fw_cfg || !fw_cfg->dma_enabled) {
536e43353fSMarc-André Lureau         error_setg(errp, "%s device requires fw_cfg with DMA",
546e43353fSMarc-André Lureau                    VMCOREINFO_DEVICE);
556e43353fSMarc-André Lureau         return;
566e43353fSMarc-André Lureau     }
576e43353fSMarc-André Lureau 
585be5df72SMarc-André Lureau     fw_cfg_add_file_callback(fw_cfg, FW_CFG_VMCOREINFO_FILENAME,
596e43353fSMarc-André Lureau                              NULL, fw_cfg_vmci_write, s,
606e43353fSMarc-André Lureau                              &s->vmcoreinfo, sizeof(s->vmcoreinfo), false);
616e43353fSMarc-André Lureau 
626e43353fSMarc-André Lureau     qemu_register_reset(vmcoreinfo_reset, dev);
63c3b1642bSMarc-André Lureau     vmcoreinfo_state = s;
646e43353fSMarc-André Lureau }
656e43353fSMarc-André Lureau 
666e43353fSMarc-André Lureau static const VMStateDescription vmstate_vmcoreinfo = {
676e43353fSMarc-André Lureau     .name = "vmcoreinfo",
686e43353fSMarc-André Lureau     .version_id = 1,
696e43353fSMarc-André Lureau     .minimum_version_id = 1,
706e43353fSMarc-André Lureau     .fields = (VMStateField[]) {
716e43353fSMarc-André Lureau         VMSTATE_BOOL(has_vmcoreinfo, VMCoreInfoState),
726e43353fSMarc-André Lureau         VMSTATE_UINT16(vmcoreinfo.host_format, VMCoreInfoState),
736e43353fSMarc-André Lureau         VMSTATE_UINT16(vmcoreinfo.guest_format, VMCoreInfoState),
746e43353fSMarc-André Lureau         VMSTATE_UINT32(vmcoreinfo.size, VMCoreInfoState),
756e43353fSMarc-André Lureau         VMSTATE_UINT64(vmcoreinfo.paddr, VMCoreInfoState),
766e43353fSMarc-André Lureau         VMSTATE_END_OF_LIST()
776e43353fSMarc-André Lureau     },
786e43353fSMarc-André Lureau };
796e43353fSMarc-André Lureau 
806e43353fSMarc-André Lureau static void vmcoreinfo_device_class_init(ObjectClass *klass, void *data)
816e43353fSMarc-André Lureau {
826e43353fSMarc-André Lureau     DeviceClass *dc = DEVICE_CLASS(klass);
836e43353fSMarc-André Lureau 
846e43353fSMarc-André Lureau     dc->vmsd = &vmstate_vmcoreinfo;
856e43353fSMarc-André Lureau     dc->realize = vmcoreinfo_realize;
866e43353fSMarc-André Lureau     dc->hotpluggable = false;
87b948bb55SMarc-André Lureau     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
886e43353fSMarc-André Lureau }
896e43353fSMarc-André Lureau 
906e43353fSMarc-André Lureau static const TypeInfo vmcoreinfo_device_info = {
916e43353fSMarc-André Lureau     .name          = VMCOREINFO_DEVICE,
926e43353fSMarc-André Lureau     .parent        = TYPE_DEVICE,
936e43353fSMarc-André Lureau     .instance_size = sizeof(VMCoreInfoState),
946e43353fSMarc-André Lureau     .class_init    = vmcoreinfo_device_class_init,
956e43353fSMarc-André Lureau };
966e43353fSMarc-André Lureau 
976e43353fSMarc-André Lureau static void vmcoreinfo_register_types(void)
986e43353fSMarc-André Lureau {
996e43353fSMarc-André Lureau     type_register_static(&vmcoreinfo_device_info);
1006e43353fSMarc-André Lureau }
1016e43353fSMarc-André Lureau 
1026e43353fSMarc-André Lureau type_init(vmcoreinfo_register_types)
103