diff options
Diffstat (limited to 'hw/misc')
-rw-r--r-- | hw/misc/Makefile.objs | 3 | ||||
-rw-r--r-- | hw/misc/bcm2835_property.c | 123 | ||||
-rw-r--r-- | hw/misc/iotkit-secctl.c | 73 | ||||
-rw-r--r-- | hw/misc/iotkit-sysctl.c | 261 | ||||
-rw-r--r-- | hw/misc/iotkit-sysinfo.c | 128 | ||||
-rw-r--r-- | hw/misc/mps2-fpgaio.c | 146 | ||||
-rw-r--r-- | hw/misc/trace-events | 16 | ||||
-rw-r--r-- | hw/misc/tz-msc.c | 308 | ||||
-rw-r--r-- | hw/misc/vmcoreinfo.c | 6 |
9 files changed, 987 insertions, 77 deletions
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index 22714b0851..6d50b03cfd 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -64,8 +64,11 @@ obj-$(CONFIG_MPS2_FPGAIO) += mps2-fpgaio.o obj-$(CONFIG_MPS2_SCC) += mps2-scc.o obj-$(CONFIG_TZ_MPC) += tz-mpc.o +obj-$(CONFIG_TZ_MSC) += tz-msc.o obj-$(CONFIG_TZ_PPC) += tz-ppc.o obj-$(CONFIG_IOTKIT_SECCTL) += iotkit-secctl.o +obj-$(CONFIG_IOTKIT_SYSCTL) += iotkit-sysctl.o +obj-$(CONFIG_IOTKIT_SYSINFO) += iotkit-sysinfo.o obj-$(CONFIG_PVPANIC) += pvpanic.o obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c index 70eaafd325..145427ae0f 100644 --- a/hw/misc/bcm2835_property.c +++ b/hw/misc/bcm2835_property.c @@ -21,11 +21,14 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) uint32_t tmp; int n; uint32_t offset, length, color; - uint32_t xres, yres, xoffset, yoffset, bpp, pixo, alpha; - uint32_t tmp_xres, tmp_yres, tmp_xoffset, tmp_yoffset; - uint32_t tmp_bpp, tmp_pixo, tmp_alpha; - uint32_t *newxres = NULL, *newyres = NULL, *newxoffset = NULL, - *newyoffset = NULL, *newbpp = NULL, *newpixo = NULL, *newalpha = NULL; + + /* + * Copy the current state of the framebuffer config; we will update + * this copy as we process tags and then ask the framebuffer to use + * it at the end. + */ + BCM2835FBConfig fbconfig = s->fbdev->config; + bool fbconfig_updated = false; value &= ~0xf; @@ -141,12 +144,9 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) /* Frame buffer */ case 0x00040001: /* Allocate buffer */ - stl_le_phys(&s->dma_as, value + 12, s->fbdev->base); - tmp_xres = newxres != NULL ? *newxres : s->fbdev->xres; - tmp_yres = newyres != NULL ? *newyres : s->fbdev->yres; - tmp_bpp = newbpp != NULL ? *newbpp : s->fbdev->bpp; + stl_le_phys(&s->dma_as, value + 12, fbconfig.base); stl_le_phys(&s->dma_as, value + 16, - tmp_xres * tmp_yres * tmp_bpp / 8); + bcm2835_fb_get_size(&fbconfig)); resplen = 8; break; case 0x00048001: /* Release buffer */ @@ -155,86 +155,85 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) case 0x00040002: /* Blank screen */ resplen = 4; break; - case 0x00040003: /* Get display width/height */ - case 0x00040004: - tmp_xres = newxres != NULL ? *newxres : s->fbdev->xres; - tmp_yres = newyres != NULL ? *newyres : s->fbdev->yres; - stl_le_phys(&s->dma_as, value + 12, tmp_xres); - stl_le_phys(&s->dma_as, value + 16, tmp_yres); + case 0x00044003: /* Test physical display width/height */ + case 0x00044004: /* Test virtual display width/height */ resplen = 8; break; - case 0x00044003: /* Test display width/height */ - case 0x00044004: + case 0x00048003: /* Set physical display width/height */ + fbconfig.xres = ldl_le_phys(&s->dma_as, value + 12); + fbconfig.yres = ldl_le_phys(&s->dma_as, value + 16); + bcm2835_fb_validate_config(&fbconfig); + fbconfig_updated = true; + /* fall through */ + case 0x00040003: /* Get physical display width/height */ + stl_le_phys(&s->dma_as, value + 12, fbconfig.xres); + stl_le_phys(&s->dma_as, value + 16, fbconfig.yres); resplen = 8; break; - case 0x00048003: /* Set display width/height */ - case 0x00048004: - xres = ldl_le_phys(&s->dma_as, value + 12); - newxres = &xres; - yres = ldl_le_phys(&s->dma_as, value + 16); - newyres = &yres; + case 0x00048004: /* Set virtual display width/height */ + fbconfig.xres_virtual = ldl_le_phys(&s->dma_as, value + 12); + fbconfig.yres_virtual = ldl_le_phys(&s->dma_as, value + 16); + bcm2835_fb_validate_config(&fbconfig); + fbconfig_updated = true; + /* fall through */ + case 0x00040004: /* Get virtual display width/height */ + stl_le_phys(&s->dma_as, value + 12, fbconfig.xres_virtual); + stl_le_phys(&s->dma_as, value + 16, fbconfig.yres_virtual); resplen = 8; break; - case 0x00040005: /* Get depth */ - tmp_bpp = newbpp != NULL ? *newbpp : s->fbdev->bpp; - stl_le_phys(&s->dma_as, value + 12, tmp_bpp); - resplen = 4; - break; case 0x00044005: /* Test depth */ resplen = 4; break; case 0x00048005: /* Set depth */ - bpp = ldl_le_phys(&s->dma_as, value + 12); - newbpp = &bpp; - resplen = 4; - break; - case 0x00040006: /* Get pixel order */ - tmp_pixo = newpixo != NULL ? *newpixo : s->fbdev->pixo; - stl_le_phys(&s->dma_as, value + 12, tmp_pixo); + fbconfig.bpp = ldl_le_phys(&s->dma_as, value + 12); + bcm2835_fb_validate_config(&fbconfig); + fbconfig_updated = true; + /* fall through */ + case 0x00040005: /* Get depth */ + stl_le_phys(&s->dma_as, value + 12, fbconfig.bpp); resplen = 4; break; case 0x00044006: /* Test pixel order */ resplen = 4; break; case 0x00048006: /* Set pixel order */ - pixo = ldl_le_phys(&s->dma_as, value + 12); - newpixo = &pixo; - resplen = 4; - break; - case 0x00040007: /* Get alpha */ - tmp_alpha = newalpha != NULL ? *newalpha : s->fbdev->alpha; - stl_le_phys(&s->dma_as, value + 12, tmp_alpha); + fbconfig.pixo = ldl_le_phys(&s->dma_as, value + 12); + bcm2835_fb_validate_config(&fbconfig); + fbconfig_updated = true; + /* fall through */ + case 0x00040006: /* Get pixel order */ + stl_le_phys(&s->dma_as, value + 12, fbconfig.pixo); resplen = 4; break; case 0x00044007: /* Test pixel alpha */ resplen = 4; break; case 0x00048007: /* Set alpha */ - alpha = ldl_le_phys(&s->dma_as, value + 12); - newalpha = α + fbconfig.alpha = ldl_le_phys(&s->dma_as, value + 12); + bcm2835_fb_validate_config(&fbconfig); + fbconfig_updated = true; + /* fall through */ + case 0x00040007: /* Get alpha */ + stl_le_phys(&s->dma_as, value + 12, fbconfig.alpha); resplen = 4; break; case 0x00040008: /* Get pitch */ - tmp_xres = newxres != NULL ? *newxres : s->fbdev->xres; - tmp_bpp = newbpp != NULL ? *newbpp : s->fbdev->bpp; - stl_le_phys(&s->dma_as, value + 12, tmp_xres * tmp_bpp / 8); + stl_le_phys(&s->dma_as, value + 12, + bcm2835_fb_get_pitch(&fbconfig)); resplen = 4; break; - case 0x00040009: /* Get virtual offset */ - tmp_xoffset = newxoffset != NULL ? *newxoffset : s->fbdev->xoffset; - tmp_yoffset = newyoffset != NULL ? *newyoffset : s->fbdev->yoffset; - stl_le_phys(&s->dma_as, value + 12, tmp_xoffset); - stl_le_phys(&s->dma_as, value + 16, tmp_yoffset); - resplen = 8; - break; case 0x00044009: /* Test virtual offset */ resplen = 8; break; case 0x00048009: /* Set virtual offset */ - xoffset = ldl_le_phys(&s->dma_as, value + 12); - newxoffset = &xoffset; - yoffset = ldl_le_phys(&s->dma_as, value + 16); - newyoffset = &yoffset; + fbconfig.xoffset = ldl_le_phys(&s->dma_as, value + 12); + fbconfig.yoffset = ldl_le_phys(&s->dma_as, value + 16); + bcm2835_fb_validate_config(&fbconfig); + fbconfig_updated = true; + /* fall through */ + case 0x00040009: /* Get virtual offset */ + stl_le_phys(&s->dma_as, value + 12, fbconfig.xoffset); + stl_le_phys(&s->dma_as, value + 16, fbconfig.yoffset); resplen = 8; break; case 0x0004000a: /* Get/Test/Set overscan */ @@ -285,10 +284,8 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) } /* Reconfigure framebuffer if required */ - if (newxres || newyres || newxoffset || newyoffset || newbpp || newpixo - || newalpha) { - bcm2835_fb_reconfigure(s->fbdev, newxres, newyres, newxoffset, - newyoffset, newbpp, newpixo, newalpha); + if (fbconfig_updated) { + bcm2835_fb_reconfigure(s->fbdev, &fbconfig); } /* Buffer response code */ diff --git a/hw/misc/iotkit-secctl.c b/hw/misc/iotkit-secctl.c index de4fd8e36d..2222b3e147 100644 --- a/hw/misc/iotkit-secctl.c +++ b/hw/misc/iotkit-secctl.c @@ -190,12 +190,13 @@ static MemTxResult iotkit_secctl_s_read(void *opaque, hwaddr addr, r = s->apbexp[offset_to_ppc_idx(offset)].sp; break; case A_SECMSCINTSTAT: + r = s->secmscintstat; + break; case A_SECMSCINTEN: + r = s->secmscinten; + break; case A_NSMSCEXP: - qemu_log_mask(LOG_UNIMP, - "IoTKit SecCtl S block read: " - "unimplemented offset 0x%x\n", offset); - r = 0; + r = s->nsmscexp; break; case A_PID4: case A_PID5: @@ -291,6 +292,23 @@ static void iotkit_secctl_ppc_update_irq_enable(IoTKitSecCtlPPC *ppc) qemu_set_irq(ppc->irq_enable, extract32(value, ppc->irq_bit_offset, 1)); } +static void iotkit_secctl_update_mscexp_irqs(qemu_irq *msc_irqs, uint32_t value) +{ + int i; + + for (i = 0; i < IOTS_NUM_EXP_MSC; i++) { + qemu_set_irq(msc_irqs[i], extract32(value, i + 16, 1)); + } +} + +static void iotkit_secctl_update_msc_irq(IoTKitSecCtl *s) +{ + /* Update the combined MSC IRQ, based on S_MSCEXP_STATUS and S_MSCEXP_EN */ + bool level = s->secmscintstat & s->secmscinten; + + qemu_set_irq(s->msc_irq, level); +} + static MemTxResult iotkit_secctl_s_write(void *opaque, hwaddr addr, uint64_t value, unsigned size, MemTxAttrs attrs) @@ -370,10 +388,15 @@ static MemTxResult iotkit_secctl_s_write(void *opaque, hwaddr addr, iotkit_secctl_ppc_sp_write(ppc, value); break; case A_SECMSCINTCLR: + iotkit_secctl_update_mscexp_irqs(s->mscexp_clear, value); + break; case A_SECMSCINTEN: - qemu_log_mask(LOG_UNIMP, - "IoTKit SecCtl S block write: " - "unimplemented offset 0x%x\n", offset); + s->secmscinten = value; + iotkit_secctl_update_msc_irq(s); + break; + case A_NSMSCEXP: + s->nsmscexp = value; + iotkit_secctl_update_mscexp_irqs(s->mscexp_ns, value); break; case A_SECMPCINTSTATUS: case A_SECPPCINTSTAT: @@ -381,7 +404,6 @@ static MemTxResult iotkit_secctl_s_write(void *opaque, hwaddr addr, case A_BRGINTSTAT: case A_AHBNSPPC0: case A_AHBSPPPC0: - case A_NSMSCEXP: case A_PID4: case A_PID5: case A_PID6: @@ -588,6 +610,14 @@ static void iotkit_secctl_mpcexp_status(void *opaque, int n, int level) s->mpcintstatus = deposit32(s->mpcintstatus, n + 16, 1, !!level); } +static void iotkit_secctl_mscexp_status(void *opaque, int n, int level) +{ + IoTKitSecCtl *s = IOTKIT_SECCTL(opaque); + + s->secmscintstat = deposit32(s->secmscintstat, n + 16, 1, !!level); + iotkit_secctl_update_msc_irq(s); +} + static void iotkit_secctl_ppc_irqstatus(void *opaque, int n, int level) { IoTKitSecCtlPPC *ppc = opaque; @@ -660,6 +690,14 @@ static void iotkit_secctl_init(Object *obj) qdev_init_gpio_in_named(dev, iotkit_secctl_mpcexp_status, "mpcexp_status", IOTS_NUM_EXP_MPC); + qdev_init_gpio_in_named(dev, iotkit_secctl_mscexp_status, + "mscexp_status", IOTS_NUM_EXP_MSC); + qdev_init_gpio_out_named(dev, s->mscexp_clear, "mscexp_clear", + IOTS_NUM_EXP_MSC); + qdev_init_gpio_out_named(dev, s->mscexp_ns, "mscexp_ns", + IOTS_NUM_EXP_MSC); + qdev_init_gpio_out_named(dev, &s->msc_irq, "msc_irq", 1); + memory_region_init_io(&s->s_regs, obj, &iotkit_secctl_s_ops, s, "iotkit-secctl-s-regs", 0x1000); memory_region_init_io(&s->ns_regs, obj, &iotkit_secctl_ns_ops, @@ -690,6 +728,24 @@ static const VMStateDescription iotkit_secctl_mpcintstatus_vmstate = { } }; +static bool needed_always(void *opaque) +{ + return true; +} + +static const VMStateDescription iotkit_secctl_msc_vmstate = { + .name = "iotkit-secctl/msc", + .version_id = 1, + .minimum_version_id = 1, + .needed = needed_always, + .fields = (VMStateField[]) { + VMSTATE_UINT32(secmscintstat, IoTKitSecCtl), + VMSTATE_UINT32(secmscinten, IoTKitSecCtl), + VMSTATE_UINT32(nsmscexp, IoTKitSecCtl), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription iotkit_secctl_vmstate = { .name = "iotkit-secctl", .version_id = 1, @@ -710,6 +766,7 @@ static const VMStateDescription iotkit_secctl_vmstate = { }, .subsections = (const VMStateDescription*[]) { &iotkit_secctl_mpcintstatus_vmstate, + &iotkit_secctl_msc_vmstate, NULL }, }; diff --git a/hw/misc/iotkit-sysctl.c b/hw/misc/iotkit-sysctl.c new file mode 100644 index 0000000000..a21d8bd678 --- /dev/null +++ b/hw/misc/iotkit-sysctl.c @@ -0,0 +1,261 @@ +/* + * ARM IoTKit system control element + * + * Copyright (c) 2018 Linaro Limited + * Written by Peter Maydell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +/* + * This is a model of the "system control element" which is part of the + * Arm IoTKit and documented in + * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html + * Specifically, it implements the "system control register" blocks. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "trace.h" +#include "qapi/error.h" +#include "sysemu/sysemu.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/misc/iotkit-sysctl.h" + +REG32(SECDBGSTAT, 0x0) +REG32(SECDBGSET, 0x4) +REG32(SECDBGCLR, 0x8) +REG32(RESET_SYNDROME, 0x100) +REG32(RESET_MASK, 0x104) +REG32(SWRESET, 0x108) + FIELD(SWRESET, SWRESETREQ, 9, 1) +REG32(GRETREG, 0x10c) +REG32(INITSVRTOR0, 0x110) +REG32(CPUWAIT, 0x118) +REG32(BUSWAIT, 0x11c) +REG32(WICCTRL, 0x120) +REG32(PID4, 0xfd0) +REG32(PID5, 0xfd4) +REG32(PID6, 0xfd8) +REG32(PID7, 0xfdc) +REG32(PID0, 0xfe0) +REG32(PID1, 0xfe4) +REG32(PID2, 0xfe8) +REG32(PID3, 0xfec) +REG32(CID0, 0xff0) +REG32(CID1, 0xff4) +REG32(CID2, 0xff8) +REG32(CID3, 0xffc) + +/* PID/CID values */ +static const int sysctl_id[] = { + 0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */ + 0x54, 0xb8, 0x0b, 0x00, /* PID0..PID3 */ + 0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */ +}; + +static uint64_t iotkit_sysctl_read(void *opaque, hwaddr offset, + unsigned size) +{ + IoTKitSysCtl *s = IOTKIT_SYSCTL(opaque); + uint64_t r; + + switch (offset) { + case A_SECDBGSTAT: + r = s->secure_debug; + break; + case A_RESET_SYNDROME: + r = s->reset_syndrome; + break; + case A_RESET_MASK: + r = s->reset_mask; + break; + case A_GRETREG: + r = s->gretreg; + break; + case A_INITSVRTOR0: + r = s->initsvrtor0; + break; + case A_CPUWAIT: + r = s->cpuwait; + break; + case A_BUSWAIT: + /* In IoTKit BUSWAIT is reserved, R/O, zero */ + r = 0; + break; + case A_WICCTRL: + r = s->wicctrl; + break; + case A_PID4 ... A_CID3: + r = sysctl_id[(offset - A_PID4) / 4]; + break; + case A_SECDBGSET: + case A_SECDBGCLR: + case A_SWRESET: + qemu_log_mask(LOG_GUEST_ERROR, + "IoTKit SysCtl read: read of WO offset %x\n", + (int)offset); + r = 0; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "IoTKit SysCtl read: bad offset %x\n", (int)offset); + r = 0; + break; + } + trace_iotkit_sysctl_read(offset, r, size); + return r; +} + +static void iotkit_sysctl_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + IoTKitSysCtl *s = IOTKIT_SYSCTL(opaque); + + trace_iotkit_sysctl_write(offset, value, size); + + /* + * Most of the state here has to do with control of reset and + * similar kinds of power up -- for instance the guest can ask + * what the reason for the last reset was, or forbid reset for + * some causes (like the non-secure watchdog). Most of this is + * not relevant to QEMU, which doesn't really model anything other + * than a full power-on reset. + * We just model the registers as reads-as-written. + */ + + switch (offset) { + case A_RESET_SYNDROME: + qemu_log_mask(LOG_UNIMP, + "IoTKit SysCtl RESET_SYNDROME unimplemented\n"); + s->reset_syndrome = value; + break; + case A_RESET_MASK: + qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl RESET_MASK unimplemented\n"); + s->reset_mask = value; + break; + case A_GRETREG: + /* + * General retention register, which is only reset by a power-on + * reset. Technically this implementation is complete, since + * QEMU only supports power-on resets... + */ + s->gretreg = value; + break; + case A_INITSVRTOR0: + qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl INITSVRTOR0 unimplemented\n"); + s->initsvrtor0 = value; + break; + case A_CPUWAIT: + qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl CPUWAIT unimplemented\n"); + s->cpuwait = value; + break; + case A_WICCTRL: + qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl WICCTRL unimplemented\n"); + s->wicctrl = value; + break; + case A_SECDBGSET: + /* write-1-to-set */ + qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl SECDBGSET unimplemented\n"); + s->secure_debug |= value; + break; + case A_SECDBGCLR: + /* write-1-to-clear */ + s->secure_debug &= ~value; + break; + case A_SWRESET: + /* One w/o bit to request a reset; all other bits reserved */ + if (value & R_SWRESET_SWRESETREQ_MASK) { + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + } + break; + case A_BUSWAIT: /* In IoTKit BUSWAIT is reserved, R/O, zero */ + case A_SECDBGSTAT: + case A_PID4 ... A_CID3: + qemu_log_mask(LOG_GUEST_ERROR, + "IoTKit SysCtl write: write of RO offset %x\n", + (int)offset); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "IoTKit SysCtl write: bad offset %x\n", (int)offset); + break; + } +} + +static const MemoryRegionOps iotkit_sysctl_ops = { + .read = iotkit_sysctl_read, + .write = iotkit_sysctl_write, + .endianness = DEVICE_LITTLE_ENDIAN, + /* byte/halfword accesses are just zero-padded on reads and writes */ + .impl.min_access_size = 4, + .impl.max_access_size = 4, + .valid.min_access_size = 1, + .valid.max_access_size = 4, +}; + +static void iotkit_sysctl_reset(DeviceState *dev) +{ + IoTKitSysCtl *s = IOTKIT_SYSCTL(dev); + + trace_iotkit_sysctl_reset(); + s->secure_debug = 0; + s->reset_syndrome = 1; + s->reset_mask = 0; + s->gretreg = 0; + s->initsvrtor0 = 0x10000000; + s->cpuwait = 0; + s->wicctrl = 0; +} + +static void iotkit_sysctl_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + IoTKitSysCtl *s = IOTKIT_SYSCTL(obj); + + memory_region_init_io(&s->iomem, obj, &iotkit_sysctl_ops, + s, "iotkit-sysctl", 0x1000); + sysbus_init_mmio(sbd, &s->iomem); +} + +static const VMStateDescription iotkit_sysctl_vmstate = { + .name = "iotkit-sysctl", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(secure_debug, IoTKitSysCtl), + VMSTATE_UINT32(reset_syndrome, IoTKitSysCtl), + VMSTATE_UINT32(reset_mask, IoTKitSysCtl), + VMSTATE_UINT32(gretreg, IoTKitSysCtl), + VMSTATE_UINT32(initsvrtor0, IoTKitSysCtl), + VMSTATE_UINT32(cpuwait, IoTKitSysCtl), + VMSTATE_UINT32(wicctrl, IoTKitSysCtl), + VMSTATE_END_OF_LIST() + } +}; + +static void iotkit_sysctl_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &iotkit_sysctl_vmstate; + dc->reset = iotkit_sysctl_reset; +} + +static const TypeInfo iotkit_sysctl_info = { + .name = TYPE_IOTKIT_SYSCTL, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IoTKitSysCtl), + .instance_init = iotkit_sysctl_init, + .class_init = iotkit_sysctl_class_init, +}; + +static void iotkit_sysctl_register_types(void) +{ + type_register_static(&iotkit_sysctl_info); +} + +type_init(iotkit_sysctl_register_types); diff --git a/hw/misc/iotkit-sysinfo.c b/hw/misc/iotkit-sysinfo.c new file mode 100644 index 0000000000..78955bc45f --- /dev/null +++ b/hw/misc/iotkit-sysinfo.c @@ -0,0 +1,128 @@ +/* + * ARM IoTKit system information block + * + * Copyright (c) 2018 Linaro Limited + * Written by Peter Maydell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +/* + * This is a model of the "system information block" which is part of the + * Arm IoTKit and documented in + * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html + * It consists of 2 read-only version/config registers, plus the + * usual ID registers. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "trace.h" +#include "qapi/error.h" +#include "sysemu/sysemu.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/misc/iotkit-sysinfo.h" + +REG32(SYS_VERSION, 0x0) +REG32(SYS_CONFIG, 0x4) +REG32(PID4, 0xfd0) +REG32(PID5, 0xfd4) +REG32(PID6, 0xfd8) +REG32(PID7, 0xfdc) +REG32(PID0, 0xfe0) +REG32(PID1, 0xfe4) +REG32(PID2, 0xfe8) +REG32(PID3, 0xfec) +REG32(CID0, 0xff0) +REG32(CID1, 0xff4) +REG32(CID2, 0xff8) +REG32(CID3, 0xffc) + +/* PID/CID values */ +static const int sysinfo_id[] = { + 0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */ + 0x58, 0xb8, 0x0b, 0x00, /* PID0..PID3 */ + 0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */ +}; + +static uint64_t iotkit_sysinfo_read(void *opaque, hwaddr offset, + unsigned size) +{ + uint64_t r; + + switch (offset) { + case A_SYS_VERSION: + r = 0x41743; + break; + + case A_SYS_CONFIG: + r = 0x31; + break; + case A_PID4 ... A_CID3: + r = sysinfo_id[(offset - A_PID4) / 4]; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "IoTKit SysInfo read: bad offset %x\n", (int)offset); + r = 0; + break; + } + trace_iotkit_sysinfo_read(offset, r, size); + return r; +} + +static void iotkit_sysinfo_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + trace_iotkit_sysinfo_write(offset, value, size); + + qemu_log_mask(LOG_GUEST_ERROR, + "IoTKit SysInfo: write to RO offset 0x%x\n", (int)offset); +} + +static const MemoryRegionOps iotkit_sysinfo_ops = { + .read = iotkit_sysinfo_read, + .write = iotkit_sysinfo_write, + .endianness = DEVICE_LITTLE_ENDIAN, + /* byte/halfword accesses are just zero-padded on reads and writes */ + .impl.min_access_size = 4, + .impl.max_access_size = 4, + .valid.min_access_size = 1, + .valid.max_access_size = 4, +}; + +static void iotkit_sysinfo_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + IoTKitSysInfo *s = IOTKIT_SYSINFO(obj); + + memory_region_init_io(&s->iomem, obj, &iotkit_sysinfo_ops, + s, "iotkit-sysinfo", 0x1000); + sysbus_init_mmio(sbd, &s->iomem); +} + +static void iotkit_sysinfo_class_init(ObjectClass *klass, void *data) +{ + /* + * This device has no guest-modifiable state and so it + * does not need a reset function or VMState. + */ +} + +static const TypeInfo iotkit_sysinfo_info = { + .name = TYPE_IOTKIT_SYSINFO, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IoTKitSysInfo), + .instance_init = iotkit_sysinfo_init, + .class_init = iotkit_sysinfo_class_init, +}; + +static void iotkit_sysinfo_register_types(void) +{ + type_register_static(&iotkit_sysinfo_info); +} + +type_init(iotkit_sysinfo_register_types); diff --git a/hw/misc/mps2-fpgaio.c b/hw/misc/mps2-fpgaio.c index 7394a057d8..5cf10ebd66 100644 --- a/hw/misc/mps2-fpgaio.c +++ b/hw/misc/mps2-fpgaio.c @@ -22,6 +22,7 @@ #include "hw/sysbus.h" #include "hw/registerfields.h" #include "hw/misc/mps2-fpgaio.h" +#include "qemu/timer.h" REG32(LED0, 0) REG32(BUTTON, 8) @@ -32,10 +33,92 @@ REG32(PRESCALE, 0x1c) REG32(PSCNTR, 0x20) REG32(MISC, 0x4c) +static uint32_t counter_from_tickoff(int64_t now, int64_t tick_offset, int frq) +{ + return muldiv64(now - tick_offset, frq, NANOSECONDS_PER_SECOND); +} + +static int64_t tickoff_from_counter(int64_t now, uint32_t count, int frq) +{ + return now - muldiv64(count, NANOSECONDS_PER_SECOND, frq); +} + +static void resync_counter(MPS2FPGAIO *s) +{ + /* + * Update s->counter and s->pscntr to their true current values + * by calculating how many times PSCNTR has ticked since the + * last time we did a resync. + */ + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + int64_t elapsed = now - s->pscntr_sync_ticks; + + /* + * Round elapsed down to a whole number of PSCNTR ticks, so we don't + * lose time if we do multiple resyncs in a single tick. + */ + uint64_t ticks = muldiv64(elapsed, s->prescale_clk, NANOSECONDS_PER_SECOND); + + /* + * Work out what PSCNTR and COUNTER have moved to. We assume that + * PSCNTR reloads from PRESCALE one tick-period after it hits zero, + * and that COUNTER increments at the same moment. + */ + if (ticks == 0) { + /* We haven't ticked since the last time we were asked */ + return; + } else if (ticks < s->pscntr) { + /* We haven't yet reached zero, just reduce the PSCNTR */ + s->pscntr -= ticks; + } else { + if (s->prescale == 0) { + /* + * If the reload value is zero then the PSCNTR will stick + * at zero once it reaches it, and so we will increment + * COUNTER every tick after that. + */ + s->counter += ticks - s->pscntr; + s->pscntr = 0; + } else { + /* + * This is the complicated bit. This ASCII art diagram gives an + * example with PRESCALE==5 PSCNTR==7: + * + * ticks 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 + * PSCNTR 7 6 5 4 3 2 1 0 5 4 3 2 1 0 5 + * cinc 1 2 + * y 0 1 2 3 4 5 6 7 8 9 10 11 12 + * x 0 1 2 3 4 5 0 1 2 3 4 5 0 + * + * where x = y % (s->prescale + 1) + * and so PSCNTR = s->prescale - x + * and COUNTER is incremented by y / (s->prescale + 1) + * + * The case where PSCNTR < PRESCALE works out the same, + * though we must be careful to calculate y as 64-bit unsigned + * for all parts of the expression. + * y < 0 is not possible because that implies ticks < s->pscntr. + */ + uint64_t y = ticks - s->pscntr + s->prescale; + s->pscntr = s->prescale - (y % (s->prescale + 1)); + s->counter += y / (s->prescale + 1); + } + } + + /* + * Only advance the sync time to the timestamp of the last PSCNTR tick, + * not all the way to 'now', so we don't lose time if we do multiple + * resyncs in a single tick. + */ + s->pscntr_sync_ticks += muldiv64(ticks, NANOSECONDS_PER_SECOND, + s->prescale_clk); +} + static uint64_t mps2_fpgaio_read(void *opaque, hwaddr offset, unsigned size) { MPS2FPGAIO *s = MPS2_FPGAIO(opaque); uint64_t r; + int64_t now; switch (offset) { case A_LED0: @@ -54,12 +137,20 @@ static uint64_t mps2_fpgaio_read(void *opaque, hwaddr offset, unsigned size) r = s->misc; break; case A_CLK1HZ: + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + r = counter_from_tickoff(now, s->clk1hz_tick_offset, 1); + break; case A_CLK100HZ: + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + r = counter_from_tickoff(now, s->clk100hz_tick_offset, 100); + break; case A_COUNTER: + resync_counter(s); + r = s->counter; + break; case A_PSCNTR: - /* These are all upcounters of various frequencies. */ - qemu_log_mask(LOG_UNIMP, "MPS2 FPGAIO: counters unimplemented\n"); - r = 0; + resync_counter(s); + r = s->pscntr; break; default: qemu_log_mask(LOG_GUEST_ERROR, @@ -76,6 +167,7 @@ static void mps2_fpgaio_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { MPS2FPGAIO *s = MPS2_FPGAIO(opaque); + int64_t now; trace_mps2_fpgaio_write(offset, value, size); @@ -89,6 +181,7 @@ static void mps2_fpgaio_write(void *opaque, hwaddr offset, uint64_t value, s->led0 = value & 0x3; break; case A_PRESCALE: + resync_counter(s); s->prescale = value; break; case A_MISC: @@ -100,6 +193,22 @@ static void mps2_fpgaio_write(void *opaque, hwaddr offset, uint64_t value, "MPS2 FPGAIO: MISC control bits unimplemented\n"); s->misc = value; break; + case A_CLK1HZ: + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + s->clk1hz_tick_offset = tickoff_from_counter(now, value, 1); + break; + case A_CLK100HZ: + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + s->clk100hz_tick_offset = tickoff_from_counter(now, value, 100); + break; + case A_COUNTER: + resync_counter(s); + s->counter = value; + break; + case A_PSCNTR: + resync_counter(s); + s->pscntr = value; + break; default: qemu_log_mask(LOG_GUEST_ERROR, "MPS2 FPGAIO write: bad offset 0x%x\n", (int) offset); @@ -116,11 +225,17 @@ static const MemoryRegionOps mps2_fpgaio_ops = { static void mps2_fpgaio_reset(DeviceState *dev) { MPS2FPGAIO *s = MPS2_FPGAIO(dev); + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); trace_mps2_fpgaio_reset(); s->led0 = 0; s->prescale = 0; s->misc = 0; + s->clk1hz_tick_offset = tickoff_from_counter(now, 0, 1); + s->clk100hz_tick_offset = tickoff_from_counter(now, 0, 100); + s->counter = 0; + s->pscntr = 0; + s->pscntr_sync_ticks = now; } static void mps2_fpgaio_init(Object *obj) @@ -133,6 +248,27 @@ static void mps2_fpgaio_init(Object *obj) sysbus_init_mmio(sbd, &s->iomem); } +static bool mps2_fpgaio_counters_needed(void *opaque) +{ + /* Currently vmstate.c insists all subsections have a 'needed' function */ + return true; +} + +static const VMStateDescription mps2_fpgaio_counters_vmstate = { + .name = "mps2-fpgaio/counters", + .version_id = 2, + .minimum_version_id = 2, + .needed = mps2_fpgaio_counters_needed, + .fields = (VMStateField[]) { + VMSTATE_INT64(clk1hz_tick_offset, MPS2FPGAIO), + VMSTATE_INT64(clk100hz_tick_offset, MPS2FPGAIO), + VMSTATE_UINT32(counter, MPS2FPGAIO), + VMSTATE_UINT32(pscntr, MPS2FPGAIO), + VMSTATE_INT64(pscntr_sync_ticks, MPS2FPGAIO), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription mps2_fpgaio_vmstate = { .name = "mps2-fpgaio", .version_id = 1, @@ -142,6 +278,10 @@ static const VMStateDescription mps2_fpgaio_vmstate = { VMSTATE_UINT32(prescale, MPS2FPGAIO), VMSTATE_UINT32(misc, MPS2FPGAIO), VMSTATE_END_OF_LIST() + }, + .subsections = (const VMStateDescription*[]) { + &mps2_fpgaio_counters_vmstate, + NULL } }; diff --git a/hw/misc/trace-events b/hw/misc/trace-events index 1341508b33..52466c77c4 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -92,6 +92,15 @@ tz_mpc_mem_blocked_write(uint64_t addr, uint64_t data, unsigned size, bool secur tz_mpc_translate(uint64_t addr, int flags, const char *idx, const char *res) "TZ MPC translate: addr 0x%" PRIx64 " flags 0x%x iommu_idx %s: %s" tz_mpc_iommu_notify(uint64_t addr) "TZ MPC iommu: notifying UNMAP/MAP for 0x%" PRIx64 +# hw/misc/tz-msc.c +tz_msc_reset(void) "TZ MSC: reset" +tz_msc_cfg_nonsec(int level) "TZ MSC: cfg_nonsec = %d" +tz_msc_cfg_sec_resp(int level) "TZ MSC: cfg_sec_resp = %d" +tz_msc_irq_enable(int level) "TZ MSC: int_enable = %d" +tz_msc_irq_clear(int level) "TZ MSC: int_clear = %d" +tz_msc_update_irq(int level) "TZ MSC: setting irq line to %d" +tz_msc_access_blocked(uint64_t offset) "TZ MSC: offset 0x%" PRIx64 " access blocked" + # hw/misc/tz-ppc.c tz_ppc_reset(void) "TZ PPC: reset" tz_ppc_cfg_nonsec(int n, int level) "TZ PPC: cfg_nonsec[%d] = %d" @@ -116,3 +125,10 @@ ccm_freq(uint32_t freq) "freq = %d\n" ccm_clock_freq(uint32_t clock, uint32_t freq) "(Clock = %d) = %d\n" ccm_read_reg(const char *reg_name, uint32_t value) "reg[%s] <= 0x%" PRIx32 "\n" ccm_write_reg(const char *reg_name, uint32_t value) "reg[%s] => 0x%" PRIx32 "\n" + +# hw/misc/iotkit-sysctl.c +iotkit_sysinfo_read(uint64_t offset, uint64_t data, unsigned size) "IoTKit SysInfo read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" +iotkit_sysinfo_write(uint64_t offset, uint64_t data, unsigned size) "IoTKit SysInfo write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" +iotkit_sysctl_read(uint64_t offset, uint64_t data, unsigned size) "IoTKit SysCtl read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" +iotkit_sysctl_write(uint64_t offset, uint64_t data, unsigned size) "IoTKit SysCtl write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" +iotkit_sysctl_reset(void) "IoTKit SysCtl: reset" diff --git a/hw/misc/tz-msc.c b/hw/misc/tz-msc.c new file mode 100644 index 0000000000..9e352044ea --- /dev/null +++ b/hw/misc/tz-msc.c @@ -0,0 +1,308 @@ +/* + * ARM TrustZone master security controller emulation + * + * Copyright (c) 2018 Linaro Limited + * Written by Peter Maydell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "trace.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/misc/tz-msc.h" + +static void tz_msc_update_irq(TZMSC *s) +{ + bool level = s->irq_status; + + trace_tz_msc_update_irq(level); + qemu_set_irq(s->irq, level); +} + +static void tz_msc_cfg_nonsec(void *opaque, int n, int level) +{ + TZMSC *s = TZ_MSC(opaque); + + trace_tz_msc_cfg_nonsec(level); + s->cfg_nonsec = level; +} + +static void tz_msc_cfg_sec_resp(void *opaque, int n, int level) +{ + TZMSC *s = TZ_MSC(opaque); + + trace_tz_msc_cfg_sec_resp(level); + s->cfg_sec_resp = level; +} + +static void tz_msc_irq_clear(void *opaque, int n, int level) +{ + TZMSC *s = TZ_MSC(opaque); + + trace_tz_msc_irq_clear(level); + + s->irq_clear = level; + if (level) { + s->irq_status = false; + tz_msc_update_irq(s); + } +} + +/* The MSC may either block a transaction by aborting it, block a + * transaction by making it RAZ/WI, allow it through with + * MemTxAttrs indicating a secure transaction, or allow it with + * MemTxAttrs indicating a non-secure transaction. + */ +typedef enum MSCAction { + MSCBlockAbort, + MSCBlockRAZWI, + MSCAllowSecure, + MSCAllowNonSecure, +} MSCAction; + +static MSCAction tz_msc_check(TZMSC *s, hwaddr addr) +{ + /* + * Check whether to allow an access from the bus master, returning + * an MSCAction indicating the required behaviour. If the transaction + * is blocked, the caller must check cfg_sec_resp to determine + * whether to abort or RAZ/WI the transaction. + */ + IDAUInterfaceClass *iic = IDAU_INTERFACE_GET_CLASS(s->idau); + IDAUInterface *ii = IDAU_INTERFACE(s->idau); + bool idau_exempt = false, idau_ns = true, idau_nsc = true; + int idau_region = IREGION_NOTVALID; + + iic->check(ii, addr, &idau_region, &idau_exempt, &idau_ns, &idau_nsc); + + if (idau_exempt) { + /* + * Uncheck region -- OK, transaction type depends on + * whether bus master is configured as Secure or NonSecure + */ + return s->cfg_nonsec ? MSCAllowNonSecure : MSCAllowSecure; + } + + if (idau_ns) { + /* NonSecure region -- always forward as NS transaction */ + return MSCAllowNonSecure; + } + + if (!s->cfg_nonsec) { + /* Access to Secure region by Secure bus master: OK */ + return MSCAllowSecure; + } + + /* Attempted access to Secure region by NS bus master: block */ + trace_tz_msc_access_blocked(addr); + if (!s->cfg_sec_resp) { + return MSCBlockRAZWI; + } + + /* + * The TRM isn't clear on behaviour if irq_clear is high when a + * transaction is blocked. We assume that the MSC behaves like the + * PPC, where holding irq_clear high suppresses the interrupt. + */ + if (!s->irq_clear) { + s->irq_status = true; + tz_msc_update_irq(s); + } + return MSCBlockAbort; +} + +static MemTxResult tz_msc_read(void *opaque, hwaddr addr, uint64_t *pdata, + unsigned size, MemTxAttrs attrs) +{ + TZMSC *s = opaque; + AddressSpace *as = &s->downstream_as; + uint64_t data; + MemTxResult res; + + switch (tz_msc_check(s, addr)) { + case MSCBlockAbort: + return MEMTX_ERROR; + case MSCBlockRAZWI: + *pdata = 0; + return MEMTX_OK; + case MSCAllowSecure: + attrs.secure = 1; + attrs.unspecified = 0; + break; + case MSCAllowNonSecure: + attrs.secure = 0; + attrs.unspecified = 0; + break; + } + + switch (size) { + case 1: + data = address_space_ldub(as, addr, attrs, &res); + break; + case 2: + data = address_space_lduw_le(as, addr, attrs, &res); + break; + case 4: + data = address_space_ldl_le(as, addr, attrs, &res); + break; + case 8: + data = address_space_ldq_le(as, addr, attrs, &res); + break; + default: + g_assert_not_reached(); + } + *pdata = data; + return res; +} + +static MemTxResult tz_msc_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size, MemTxAttrs attrs) +{ + TZMSC *s = opaque; + AddressSpace *as = &s->downstream_as; + MemTxResult res; + + switch (tz_msc_check(s, addr)) { + case MSCBlockAbort: + return MEMTX_ERROR; + case MSCBlockRAZWI: + return MEMTX_OK; + case MSCAllowSecure: + attrs.secure = 1; + attrs.unspecified = 0; + break; + case MSCAllowNonSecure: + attrs.secure = 0; + attrs.unspecified = 0; + break; + } + + switch (size) { + case 1: + address_space_stb(as, addr, val, attrs, &res); + break; + case 2: + address_space_stw_le(as, addr, val, attrs, &res); + break; + case 4: + address_space_stl_le(as, addr, val, attrs, &res); + break; + case 8: + address_space_stq_le(as, addr, val, attrs, &res); + break; + default: + g_assert_not_reached(); + } + return res; +} + +static const MemoryRegionOps tz_msc_ops = { + .read_with_attrs = tz_msc_read, + .write_with_attrs = tz_msc_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void tz_msc_reset(DeviceState *dev) +{ + TZMSC *s = TZ_MSC(dev); + + trace_tz_msc_reset(); + s->cfg_sec_resp = false; + s->cfg_nonsec = false; + s->irq_clear = 0; + s->irq_status = 0; +} + +static void tz_msc_init(Object *obj) +{ + DeviceState *dev = DEVICE(obj); + TZMSC *s = TZ_MSC(obj); + + qdev_init_gpio_in_named(dev, tz_msc_cfg_nonsec, "cfg_nonsec", 1); + qdev_init_gpio_in_named(dev, tz_msc_cfg_sec_resp, "cfg_sec_resp", 1); + qdev_init_gpio_in_named(dev, tz_msc_irq_clear, "irq_clear", 1); + qdev_init_gpio_out_named(dev, &s->irq, "irq", 1); +} + +static void tz_msc_realize(DeviceState *dev, Error **errp) +{ + Object *obj = OBJECT(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + TZMSC *s = TZ_MSC(dev); + const char *name = "tz-msc-downstream"; + uint64_t size; + + /* + * We can't create the upstream end of the port until realize, + * as we don't know the size of the MR used as the downstream until then. + * We insist on having a downstream, to avoid complicating the + * code with handling the "don't know how big this is" case. It's easy + * enough for the user to create an unimplemented_device as downstream + * if they have nothing else to plug into this. + */ + if (!s->downstream) { + error_setg(errp, "MSC 'downstream' link not set"); + return; + } + if (!s->idau) { + error_setg(errp, "MSC 'idau' link not set"); + return; + } + + size = memory_region_size(s->downstream); + address_space_init(&s->downstream_as, s->downstream, name); + memory_region_init_io(&s->upstream, obj, &tz_msc_ops, s, name, size); + sysbus_init_mmio(sbd, &s->upstream); +} + +static const VMStateDescription tz_msc_vmstate = { + .name = "tz-msc", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_BOOL(cfg_nonsec, TZMSC), + VMSTATE_BOOL(cfg_sec_resp, TZMSC), + VMSTATE_BOOL(irq_clear, TZMSC), + VMSTATE_BOOL(irq_status, TZMSC), + VMSTATE_END_OF_LIST() + } +}; + +static Property tz_msc_properties[] = { + DEFINE_PROP_LINK("downstream", TZMSC, downstream, + TYPE_MEMORY_REGION, MemoryRegion *), + DEFINE_PROP_LINK("idau", TZMSC, idau, + TYPE_IDAU_INTERFACE, IDAUInterface *), + DEFINE_PROP_END_OF_LIST(), +}; + +static void tz_msc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = tz_msc_realize; + dc->vmsd = &tz_msc_vmstate; + dc->reset = tz_msc_reset; + dc->props = tz_msc_properties; +} + +static const TypeInfo tz_msc_info = { + .name = TYPE_TZ_MSC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(TZMSC), + .instance_init = tz_msc_init, + .class_init = tz_msc_class_init, +}; + +static void tz_msc_register_types(void) +{ + type_register_static(&tz_msc_info); +} + +type_init(tz_msc_register_types); diff --git a/hw/misc/vmcoreinfo.c b/hw/misc/vmcoreinfo.c index a2805527cb..304c6287c7 100644 --- a/hw/misc/vmcoreinfo.c +++ b/hw/misc/vmcoreinfo.c @@ -19,7 +19,7 @@ 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 != VMCOREINFO_FORMAT_NONE; + && s->vmcoreinfo.guest_format != FW_CFG_VMCOREINFO_FORMAT_NONE; } static void vmcoreinfo_reset(void *dev) @@ -28,7 +28,7 @@ static void vmcoreinfo_reset(void *dev) s->has_vmcoreinfo = false; memset(&s->vmcoreinfo, 0, sizeof(s->vmcoreinfo)); - s->vmcoreinfo.host_format = cpu_to_le16(VMCOREINFO_FORMAT_ELF); + s->vmcoreinfo.host_format = cpu_to_le16(FW_CFG_VMCOREINFO_FORMAT_ELF); } static void vmcoreinfo_realize(DeviceState *dev, Error **errp) @@ -53,7 +53,7 @@ static void vmcoreinfo_realize(DeviceState *dev, Error **errp) return; } - fw_cfg_add_file_callback(fw_cfg, "etc/vmcoreinfo", + fw_cfg_add_file_callback(fw_cfg, FW_CFG_VMCOREINFO_FILENAME, NULL, fw_cfg_vmci_write, s, &s->vmcoreinfo, sizeof(s->vmcoreinfo), false); |