xref: /openbmc/qemu/hw/misc/vmcoreinfo.c (revision b948bb55dac527ae6b0c5e6dc69d00866a3a6fee)
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  */
126e43353fSMarc-André Lureau #include "qemu/osdep.h"
136e43353fSMarc-André Lureau #include "qapi/error.h"
146e43353fSMarc-André Lureau #include "hw/nvram/fw_cfg.h"
156e43353fSMarc-André Lureau #include "hw/misc/vmcoreinfo.h"
166e43353fSMarc-André Lureau 
176e43353fSMarc-André Lureau static void fw_cfg_vmci_write(void *dev, off_t offset, size_t len)
186e43353fSMarc-André Lureau {
196e43353fSMarc-André Lureau     VMCoreInfoState *s = VMCOREINFO(dev);
206e43353fSMarc-André Lureau 
216e43353fSMarc-André Lureau     s->has_vmcoreinfo = offset == 0 && len == sizeof(s->vmcoreinfo)
226e43353fSMarc-André Lureau         && s->vmcoreinfo.guest_format != VMCOREINFO_FORMAT_NONE;
236e43353fSMarc-André Lureau }
246e43353fSMarc-André Lureau 
256e43353fSMarc-André Lureau static void vmcoreinfo_reset(void *dev)
266e43353fSMarc-André Lureau {
276e43353fSMarc-André Lureau     VMCoreInfoState *s = VMCOREINFO(dev);
286e43353fSMarc-André Lureau 
296e43353fSMarc-André Lureau     s->has_vmcoreinfo = false;
306e43353fSMarc-André Lureau     memset(&s->vmcoreinfo, 0, sizeof(s->vmcoreinfo));
316e43353fSMarc-André Lureau     s->vmcoreinfo.host_format = cpu_to_le16(VMCOREINFO_FORMAT_ELF);
326e43353fSMarc-André Lureau }
336e43353fSMarc-André Lureau 
346e43353fSMarc-André Lureau static void vmcoreinfo_realize(DeviceState *dev, Error **errp)
356e43353fSMarc-André Lureau {
366e43353fSMarc-André Lureau     VMCoreInfoState *s = VMCOREINFO(dev);
376e43353fSMarc-André Lureau     FWCfgState *fw_cfg = fw_cfg_find();
386e43353fSMarc-André Lureau 
396e43353fSMarc-André Lureau     /* Given that this function is executing, there is at least one VMCOREINFO
406e43353fSMarc-André Lureau      * device. Check if there are several.
416e43353fSMarc-André Lureau      */
426e43353fSMarc-André Lureau     if (!vmcoreinfo_find()) {
436e43353fSMarc-André Lureau         error_setg(errp, "at most one %s device is permitted",
446e43353fSMarc-André Lureau                    VMCOREINFO_DEVICE);
456e43353fSMarc-André Lureau         return;
466e43353fSMarc-André Lureau     }
476e43353fSMarc-André Lureau 
486e43353fSMarc-André Lureau     if (!fw_cfg || !fw_cfg->dma_enabled) {
496e43353fSMarc-André Lureau         error_setg(errp, "%s device requires fw_cfg with DMA",
506e43353fSMarc-André Lureau                    VMCOREINFO_DEVICE);
516e43353fSMarc-André Lureau         return;
526e43353fSMarc-André Lureau     }
536e43353fSMarc-André Lureau 
546e43353fSMarc-André Lureau     fw_cfg_add_file_callback(fw_cfg, "etc/vmcoreinfo",
556e43353fSMarc-André Lureau                              NULL, fw_cfg_vmci_write, s,
566e43353fSMarc-André Lureau                              &s->vmcoreinfo, sizeof(s->vmcoreinfo), false);
576e43353fSMarc-André Lureau 
586e43353fSMarc-André Lureau     qemu_register_reset(vmcoreinfo_reset, dev);
596e43353fSMarc-André Lureau }
606e43353fSMarc-André Lureau 
616e43353fSMarc-André Lureau static const VMStateDescription vmstate_vmcoreinfo = {
626e43353fSMarc-André Lureau     .name = "vmcoreinfo",
636e43353fSMarc-André Lureau     .version_id = 1,
646e43353fSMarc-André Lureau     .minimum_version_id = 1,
656e43353fSMarc-André Lureau     .fields = (VMStateField[]) {
666e43353fSMarc-André Lureau         VMSTATE_BOOL(has_vmcoreinfo, VMCoreInfoState),
676e43353fSMarc-André Lureau         VMSTATE_UINT16(vmcoreinfo.host_format, VMCoreInfoState),
686e43353fSMarc-André Lureau         VMSTATE_UINT16(vmcoreinfo.guest_format, VMCoreInfoState),
696e43353fSMarc-André Lureau         VMSTATE_UINT32(vmcoreinfo.size, VMCoreInfoState),
706e43353fSMarc-André Lureau         VMSTATE_UINT64(vmcoreinfo.paddr, VMCoreInfoState),
716e43353fSMarc-André Lureau         VMSTATE_END_OF_LIST()
726e43353fSMarc-André Lureau     },
736e43353fSMarc-André Lureau };
746e43353fSMarc-André Lureau 
756e43353fSMarc-André Lureau static void vmcoreinfo_device_class_init(ObjectClass *klass, void *data)
766e43353fSMarc-André Lureau {
776e43353fSMarc-André Lureau     DeviceClass *dc = DEVICE_CLASS(klass);
786e43353fSMarc-André Lureau 
796e43353fSMarc-André Lureau     dc->vmsd = &vmstate_vmcoreinfo;
806e43353fSMarc-André Lureau     dc->realize = vmcoreinfo_realize;
816e43353fSMarc-André Lureau     dc->hotpluggable = false;
82*b948bb55SMarc-André Lureau     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
836e43353fSMarc-André Lureau }
846e43353fSMarc-André Lureau 
856e43353fSMarc-André Lureau static const TypeInfo vmcoreinfo_device_info = {
866e43353fSMarc-André Lureau     .name          = VMCOREINFO_DEVICE,
876e43353fSMarc-André Lureau     .parent        = TYPE_DEVICE,
886e43353fSMarc-André Lureau     .instance_size = sizeof(VMCoreInfoState),
896e43353fSMarc-André Lureau     .class_init    = vmcoreinfo_device_class_init,
906e43353fSMarc-André Lureau };
916e43353fSMarc-André Lureau 
926e43353fSMarc-André Lureau static void vmcoreinfo_register_types(void)
936e43353fSMarc-André Lureau {
946e43353fSMarc-André Lureau     type_register_static(&vmcoreinfo_device_info);
956e43353fSMarc-André Lureau }
966e43353fSMarc-André Lureau 
976e43353fSMarc-André Lureau type_init(vmcoreinfo_register_types)
98