qemu/hw/misc/iotkit-sysctl.c
Daniel P. Berrangé efba15959c qom: simplify object_find_property / object_class_find_property
When debugging QEMU it is often useful to put a breakpoint on the
error_setg_internal method impl.

Unfortunately the object_property_add / object_class_property_add
methods call object_property_find / object_class_property_find methods
to check if a property exists already before adding the new property.

As a result there are a huge number of calls to error_setg_internal
on startup of most QEMU commands, making it very painful to set a
breakpoint on this method.

Most callers of object_find_property and object_class_find_property,
however, pass in a NULL for the Error parameter. This simplifies the
methods to remove the Error parameter entirely, and then adds some
new wrapper methods that are able to raise an Error when needed.

Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Message-Id: <20200914135617.1493072-1-berrange@redhat.com>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
2020-09-22 16:45:16 -04:00

528 lines
15 KiB
C

/*
* 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/bitops.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "sysemu/runstate.h"
#include "trace.h"
#include "qapi/error.h"
#include "hw/sysbus.h"
#include "migration/vmstate.h"
#include "hw/registerfields.h"
#include "hw/misc/iotkit-sysctl.h"
#include "hw/qdev-properties.h"
#include "target/arm/arm-powerctl.h"
#include "target/arm/cpu.h"
REG32(SECDBGSTAT, 0x0)
REG32(SECDBGSET, 0x4)
REG32(SECDBGCLR, 0x8)
REG32(SCSECCTRL, 0xc)
REG32(FCLK_DIV, 0x10)
REG32(SYSCLK_DIV, 0x14)
REG32(CLOCK_FORCE, 0x18)
REG32(RESET_SYNDROME, 0x100)
REG32(RESET_MASK, 0x104)
REG32(SWRESET, 0x108)
FIELD(SWRESET, SWRESETREQ, 9, 1)
REG32(GRETREG, 0x10c)
REG32(INITSVTOR0, 0x110)
REG32(INITSVTOR1, 0x114)
REG32(CPUWAIT, 0x118)
REG32(NMI_ENABLE, 0x11c) /* BUSWAIT in IoTKit */
REG32(WICCTRL, 0x120)
REG32(EWCTRL, 0x124)
REG32(PDCM_PD_SYS_SENSE, 0x200)
REG32(PDCM_PD_SRAM0_SENSE, 0x20c)
REG32(PDCM_PD_SRAM1_SENSE, 0x210)
REG32(PDCM_PD_SRAM2_SENSE, 0x214)
REG32(PDCM_PD_SRAM3_SENSE, 0x218)
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 */
};
/*
* Set the initial secure vector table offset address for the core.
* This will take effect when the CPU next resets.
*/
static void set_init_vtor(uint64_t cpuid, uint32_t vtor)
{
Object *cpuobj = OBJECT(arm_get_cpu_by_id(cpuid));
if (cpuobj) {
if (object_property_find(cpuobj, "init-svtor")) {
object_property_set_uint(cpuobj, "init-svtor", vtor, &error_abort);
}
}
}
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_SCSECCTRL:
if (!s->is_sse200) {
goto bad_offset;
}
r = s->scsecctrl;
break;
case A_FCLK_DIV:
if (!s->is_sse200) {
goto bad_offset;
}
r = s->fclk_div;
break;
case A_SYSCLK_DIV:
if (!s->is_sse200) {
goto bad_offset;
}
r = s->sysclk_div;
break;
case A_CLOCK_FORCE:
if (!s->is_sse200) {
goto bad_offset;
}
r = s->clock_force;
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_INITSVTOR0:
r = s->initsvtor0;
break;
case A_INITSVTOR1:
if (!s->is_sse200) {
goto bad_offset;
}
r = s->initsvtor1;
break;
case A_CPUWAIT:
r = s->cpuwait;
break;
case A_NMI_ENABLE:
/* In IoTKit this is named BUSWAIT but is marked reserved, R/O, zero */
if (!s->is_sse200) {
r = 0;
break;
}
r = s->nmi_enable;
break;
case A_WICCTRL:
r = s->wicctrl;
break;
case A_EWCTRL:
if (!s->is_sse200) {
goto bad_offset;
}
r = s->ewctrl;
break;
case A_PDCM_PD_SYS_SENSE:
if (!s->is_sse200) {
goto bad_offset;
}
r = s->pdcm_pd_sys_sense;
break;
case A_PDCM_PD_SRAM0_SENSE:
if (!s->is_sse200) {
goto bad_offset;
}
r = s->pdcm_pd_sram0_sense;
break;
case A_PDCM_PD_SRAM1_SENSE:
if (!s->is_sse200) {
goto bad_offset;
}
r = s->pdcm_pd_sram1_sense;
break;
case A_PDCM_PD_SRAM2_SENSE:
if (!s->is_sse200) {
goto bad_offset;
}
r = s->pdcm_pd_sram2_sense;
break;
case A_PDCM_PD_SRAM3_SENSE:
if (!s->is_sse200) {
goto bad_offset;
}
r = s->pdcm_pd_sram3_sense;
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:
bad_offset:
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_INITSVTOR0:
s->initsvtor0 = value;
set_init_vtor(0, s->initsvtor0);
break;
case A_CPUWAIT:
if ((s->cpuwait & 1) && !(value & 1)) {
/* Powering up CPU 0 */
arm_set_cpu_on_and_reset(0);
}
if ((s->cpuwait & 2) && !(value & 2)) {
/* Powering up CPU 1 */
arm_set_cpu_on_and_reset(1);
}
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_SCSECCTRL:
if (!s->is_sse200) {
goto bad_offset;
}
qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl SCSECCTRL unimplemented\n");
s->scsecctrl = value;
break;
case A_FCLK_DIV:
if (!s->is_sse200) {
goto bad_offset;
}
qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl FCLK_DIV unimplemented\n");
s->fclk_div = value;
break;
case A_SYSCLK_DIV:
if (!s->is_sse200) {
goto bad_offset;
}
qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl SYSCLK_DIV unimplemented\n");
s->sysclk_div = value;
break;
case A_CLOCK_FORCE:
if (!s->is_sse200) {
goto bad_offset;
}
qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl CLOCK_FORCE unimplemented\n");
s->clock_force = value;
break;
case A_INITSVTOR1:
if (!s->is_sse200) {
goto bad_offset;
}
s->initsvtor1 = value;
set_init_vtor(1, s->initsvtor1);
break;
case A_EWCTRL:
if (!s->is_sse200) {
goto bad_offset;
}
qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl EWCTRL unimplemented\n");
s->ewctrl = value;
break;
case A_PDCM_PD_SYS_SENSE:
if (!s->is_sse200) {
goto bad_offset;
}
qemu_log_mask(LOG_UNIMP,
"IoTKit SysCtl PDCM_PD_SYS_SENSE unimplemented\n");
s->pdcm_pd_sys_sense = value;
break;
case A_PDCM_PD_SRAM0_SENSE:
if (!s->is_sse200) {
goto bad_offset;
}
qemu_log_mask(LOG_UNIMP,
"IoTKit SysCtl PDCM_PD_SRAM0_SENSE unimplemented\n");
s->pdcm_pd_sram0_sense = value;
break;
case A_PDCM_PD_SRAM1_SENSE:
if (!s->is_sse200) {
goto bad_offset;
}
qemu_log_mask(LOG_UNIMP,
"IoTKit SysCtl PDCM_PD_SRAM1_SENSE unimplemented\n");
s->pdcm_pd_sram1_sense = value;
break;
case A_PDCM_PD_SRAM2_SENSE:
if (!s->is_sse200) {
goto bad_offset;
}
qemu_log_mask(LOG_UNIMP,
"IoTKit SysCtl PDCM_PD_SRAM2_SENSE unimplemented\n");
s->pdcm_pd_sram2_sense = value;
break;
case A_PDCM_PD_SRAM3_SENSE:
if (!s->is_sse200) {
goto bad_offset;
}
qemu_log_mask(LOG_UNIMP,
"IoTKit SysCtl PDCM_PD_SRAM3_SENSE unimplemented\n");
s->pdcm_pd_sram3_sense = value;
break;
case A_NMI_ENABLE:
/* In IoTKit this is BUSWAIT: reserved, R/O, zero */
if (!s->is_sse200) {
goto ro_offset;
}
qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl NMI_ENABLE unimplemented\n");
s->nmi_enable = value;
break;
case A_SECDBGSTAT:
case A_PID4 ... A_CID3:
ro_offset:
qemu_log_mask(LOG_GUEST_ERROR,
"IoTKit SysCtl write: write of RO offset %x\n",
(int)offset);
break;
default:
bad_offset:
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->initsvtor0 = s->initsvtor0_rst;
s->initsvtor1 = s->initsvtor1_rst;
s->cpuwait = s->cpuwait_rst;
s->wicctrl = 0;
s->scsecctrl = 0;
s->fclk_div = 0;
s->sysclk_div = 0;
s->clock_force = 0;
s->nmi_enable = 0;
s->ewctrl = 0;
s->pdcm_pd_sys_sense = 0x7f;
s->pdcm_pd_sram0_sense = 0;
s->pdcm_pd_sram1_sense = 0;
s->pdcm_pd_sram2_sense = 0;
s->pdcm_pd_sram3_sense = 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 void iotkit_sysctl_realize(DeviceState *dev, Error **errp)
{
IoTKitSysCtl *s = IOTKIT_SYSCTL(dev);
/* The top 4 bits of the SYS_VERSION register tell us if we're an SSE-200 */
if (extract32(s->sys_version, 28, 4) == 2) {
s->is_sse200 = true;
}
}
static bool sse200_needed(void *opaque)
{
IoTKitSysCtl *s = IOTKIT_SYSCTL(opaque);
return s->is_sse200;
}
static const VMStateDescription iotkit_sysctl_sse200_vmstate = {
.name = "iotkit-sysctl/sse-200",
.version_id = 1,
.minimum_version_id = 1,
.needed = sse200_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT32(scsecctrl, IoTKitSysCtl),
VMSTATE_UINT32(fclk_div, IoTKitSysCtl),
VMSTATE_UINT32(sysclk_div, IoTKitSysCtl),
VMSTATE_UINT32(clock_force, IoTKitSysCtl),
VMSTATE_UINT32(initsvtor1, IoTKitSysCtl),
VMSTATE_UINT32(nmi_enable, IoTKitSysCtl),
VMSTATE_UINT32(pdcm_pd_sys_sense, IoTKitSysCtl),
VMSTATE_UINT32(pdcm_pd_sram0_sense, IoTKitSysCtl),
VMSTATE_UINT32(pdcm_pd_sram1_sense, IoTKitSysCtl),
VMSTATE_UINT32(pdcm_pd_sram2_sense, IoTKitSysCtl),
VMSTATE_UINT32(pdcm_pd_sram3_sense, IoTKitSysCtl),
VMSTATE_END_OF_LIST()
}
};
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(initsvtor0, IoTKitSysCtl),
VMSTATE_UINT32(cpuwait, IoTKitSysCtl),
VMSTATE_UINT32(wicctrl, IoTKitSysCtl),
VMSTATE_END_OF_LIST()
},
.subsections = (const VMStateDescription*[]) {
&iotkit_sysctl_sse200_vmstate,
NULL
}
};
static Property iotkit_sysctl_props[] = {
DEFINE_PROP_UINT32("SYS_VERSION", IoTKitSysCtl, sys_version, 0),
DEFINE_PROP_UINT32("CPUWAIT_RST", IoTKitSysCtl, cpuwait_rst, 0),
DEFINE_PROP_UINT32("INITSVTOR0_RST", IoTKitSysCtl, initsvtor0_rst,
0x10000000),
DEFINE_PROP_UINT32("INITSVTOR1_RST", IoTKitSysCtl, initsvtor1_rst,
0x10000000),
DEFINE_PROP_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;
device_class_set_props(dc, iotkit_sysctl_props);
dc->realize = iotkit_sysctl_realize;
}
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);