Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20180824-1' into staging

target-arm queue:
 * Fix rounding errors in scaling float-to-int and int-to-float operations
 * Connect virtualization-related IRQs and memory regions of GICv2
   in boards that use Cortex-A7 or Cortex-A15
 * Support taking exceptions to AArch32 Hyp mode
 * Clear CPSR.IL and CPSR.J on 32-bit exception entry
   (a minor bug fix that won't affect non-buggy guest code)
 * mps2-an505: Implement various missing devices:
   dual timer, watchdogs, counters in the FPGAIO registers,
   some missing ID/control registers, TrustZone Master Security
   Controllers, PL081 DMA controllers, PL022 SPI controllers
 * correct ID register values for mps2-an385, -an511, -an505
 * fix some hardcoded tabs in untouched backwaters of the
   target/arm codebase
 * raspi: Refactor framebuffer property handling code and implement
   support for the virtual framebuffer/viewport

# gpg: Signature made Fri 24 Aug 2018 13:19:04 BST
# gpg:                using RSA key 3C2525ED14360CDE
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>"
# gpg:                 aka "Peter Maydell <pmaydell@gmail.com>"
# gpg:                 aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>"
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83  15CF 3C25 25ED 1436 0CDE

* remotes/pmaydell/tags/pull-target-arm-20180824-1: (52 commits)
  hw/arm/mps2: Fix ID register errors on AN511 and AN385
  hw/display/bcm2835_fb: Validate bcm2835_fb_mbox_push() config
  hw/display/bcm2835_fb: Validate config settings
  hw/display/bcm2835_fb: Fix handling of virtual framebuffer
  hw/display/bcm2835_fb: Abstract out calculation of pitch, size
  hw/display/bcm2835_fb: Reset resolution, etc correctly
  hw/display/bcm2835_fb: Drop unused size and pitch fields
  hw/misc/bcm2835_property: Track fb settings using BCM2835FBConfig
  hw/misc/bcm2835_fb: Move config fields to their own struct
  target/arm: Remove a handful of stray tabs
  target/arm: Untabify iwmmxt_helper.c
  target/arm: Untabify translate.c
  hw/arm/mps2-tz: Fix MPS2 SCC config register values
  hw/arm/mps2-tz: Instantiate SPI controllers
  hw/ssi/pl022: Correct wrong DMACR and ICR handling
  hw/ssi/pl022: Correct wrong value for PL022_INT_RT
  hw/ssi/pl022: Use DeviceState::realize rather than SysBusDevice::init
  hw/ssi/pl022: Don't directly call vmstate_register()
  hw/ssi/pl022: Set up reset function in class init
  hw/ssi/pl022: Allow use as embedded-struct device
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell
2018-08-24 13:29:07 +01:00
41 changed files with 3405 additions and 718 deletions
+10
View File
@@ -451,10 +451,14 @@ F: hw/gpio/pl061.c
F: hw/input/pl050.c
F: hw/intc/pl190.c
F: hw/sd/pl181.c
F: hw/ssi/pl022.c
F: include/hw/ssi/pl022.h
F: hw/timer/pl031.c
F: include/hw/arm/primecell.h
F: hw/timer/cmsdk-apb-timer.c
F: include/hw/timer/cmsdk-apb-timer.h
F: hw/timer/cmsdk-apb-dualtimer.c
F: include/hw/timer/cmsdk-apb-dualtimer.h
F: hw/char/cmsdk-apb-uart.c
F: include/hw/char/cmsdk-apb-uart.h
F: hw/watchdog/cmsdk-apb-watchdog.c
@@ -463,6 +467,8 @@ F: hw/misc/tz-ppc.c
F: include/hw/misc/tz-ppc.h
F: hw/misc/tz-mpc.c
F: include/hw/misc/tz-mpc.h
F: hw/misc/tz-msc.c
F: include/hw/misc/tz-msc.h
ARM cores
M: Peter Maydell <peter.maydell@linaro.org>
@@ -537,6 +543,10 @@ F: hw/misc/mps2-*.c
F: include/hw/misc/mps2-*.h
F: hw/arm/iotkit.c
F: include/hw/arm/iotkit.h
F: hw/misc/iotkit-sysctl.c
F: include/hw/misc/iotkit-sysctl.h
F: hw/misc/iotkit-sysinfo.c
F: include/hw/misc/iotkit-sysinfo.h
Musicpal
M: Jan Kiszka <jan.kiszka@web.de>
+4
View File
@@ -103,6 +103,7 @@ CONFIG_STM32F2XX_SPI=y
CONFIG_STM32F205_SOC=y
CONFIG_CMSDK_APB_TIMER=y
CONFIG_CMSDK_APB_DUALTIMER=y
CONFIG_CMSDK_APB_UART=y
CONFIG_CMSDK_APB_WATCHDOG=y
@@ -110,9 +111,12 @@ CONFIG_MPS2_FPGAIO=y
CONFIG_MPS2_SCC=y
CONFIG_TZ_MPC=y
CONFIG_TZ_MSC=y
CONFIG_TZ_PPC=y
CONFIG_IOTKIT=y
CONFIG_IOTKIT_SECCTL=y
CONFIG_IOTKIT_SYSCTL=y
CONFIG_IOTKIT_SYSINFO=y
CONFIG_VERSATILE=y
CONFIG_VERSATILE_PCI=y
+455 -124
View File
File diff suppressed because it is too large Load Diff
+11
View File
@@ -736,6 +736,17 @@ static void do_cpu_reset(void *opaque)
}
}
if (!env->aarch64 && !info->secure_boot &&
arm_feature(env, ARM_FEATURE_EL2)) {
/*
* This is an AArch32 boot not to Secure state, and
* we have Hyp mode available, so boot the kernel into
* Hyp mode. This is not how the CPU comes out of reset,
* so we need to manually put it there.
*/
cpsr_write(env, ARM_CPU_MODE_HYP, CPSR_M, CPSRWriteRaw);
}
if (cs == first_cpu) {
AddressSpace *as = arm_boot_address_space(cpu, info);
+4
View File
@@ -207,6 +207,10 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp)
irq = qdev_get_gpio_in(d, ARM_CPU_IRQ);
sysbus_connect_irq(sbd, i, irq);
sysbus_connect_irq(sbd, i + smp_cpus, qdev_get_gpio_in(d, ARM_CPU_FIQ));
sysbus_connect_irq(sbd, i + 2 * smp_cpus,
qdev_get_gpio_in(d, ARM_CPU_VIRQ));
sysbus_connect_irq(sbd, i + 3 * smp_cpus,
qdev_get_gpio_in(d, ARM_CPU_VFIQ));
}
/*
+4
View File
@@ -209,6 +209,10 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(sbd, i, irq);
irq = qdev_get_gpio_in(d, ARM_CPU_FIQ);
sysbus_connect_irq(sbd, i + smp_cpus, irq);
irq = qdev_get_gpio_in(d, ARM_CPU_VIRQ);
sysbus_connect_irq(sbd, i + 2 * smp_cpus, irq);
irq = qdev_get_gpio_in(d, ARM_CPU_VFIQ);
sysbus_connect_irq(sbd, i + 3 * smp_cpus, irq);
}
/*
+6
View File
@@ -243,6 +243,8 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
int n;
qemu_irq cpu_irq[4];
qemu_irq cpu_fiq[4];
qemu_irq cpu_virq[4];
qemu_irq cpu_vfiq[4];
MemoryRegion *sysram;
MemoryRegion *dram;
MemoryRegion *sysmem;
@@ -282,6 +284,8 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
object_property_set_bool(cpuobj, true, "realized", &error_fatal);
cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ);
cpu_fiq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ);
cpu_virq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_VIRQ);
cpu_vfiq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_VFIQ);
}
sysmem = get_system_memory();
@@ -329,6 +333,8 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
for (n = 0; n < smp_cpus; n++) {
sysbus_connect_irq(busdev, n, cpu_irq[n]);
sysbus_connect_irq(busdev, n + smp_cpus, cpu_fiq[n]);
sysbus_connect_irq(busdev, n + 2 * smp_cpus, cpu_virq[n]);
sysbus_connect_irq(busdev, n + 3 * smp_cpus, cpu_vfiq[n]);
}
for (n = 0; n < 128; n++) {
+97 -17
View File
@@ -16,9 +16,11 @@
#include "hw/sysbus.h"
#include "hw/registerfields.h"
#include "hw/arm/iotkit.h"
#include "hw/misc/unimp.h"
#include "hw/arm/arm.h"
/* Clock frequency in HZ of the 32KHz "slow clock" */
#define S32KCLK (32 * 1000)
/* Create an alias region of @size bytes starting at @base
* which mirrors the memory starting at @orig.
*/
@@ -138,8 +140,23 @@ static void iotkit_init(Object *obj)
TYPE_CMSDK_APB_TIMER);
sysbus_init_child_obj(obj, "timer1", &s->timer1, sizeof(s->timer1),
TYPE_CMSDK_APB_TIMER);
sysbus_init_child_obj(obj, "s32ktimer", &s->s32ktimer, sizeof(s->s32ktimer),
TYPE_CMSDK_APB_TIMER);
sysbus_init_child_obj(obj, "dualtimer", &s->dualtimer, sizeof(s->dualtimer),
TYPE_UNIMPLEMENTED_DEVICE);
TYPE_CMSDK_APB_DUALTIMER);
sysbus_init_child_obj(obj, "s32kwatchdog", &s->s32kwatchdog,
sizeof(s->s32kwatchdog), TYPE_CMSDK_APB_WATCHDOG);
sysbus_init_child_obj(obj, "nswatchdog", &s->nswatchdog,
sizeof(s->nswatchdog), TYPE_CMSDK_APB_WATCHDOG);
sysbus_init_child_obj(obj, "swatchdog", &s->swatchdog,
sizeof(s->swatchdog), TYPE_CMSDK_APB_WATCHDOG);
sysbus_init_child_obj(obj, "iotkit-sysctl", &s->sysctl,
sizeof(s->sysctl), TYPE_IOTKIT_SYSCTL);
sysbus_init_child_obj(obj, "iotkit-sysinfo", &s->sysinfo,
sizeof(s->sysinfo), TYPE_IOTKIT_SYSINFO);
object_initialize_child(obj, "nmi-orgate", &s->nmi_orgate,
sizeof(s->nmi_orgate), TYPE_OR_IRQ,
&error_abort, NULL);
object_initialize_child(obj, "ppc-irq-orgate", &s->ppc_irq_orgate,
sizeof(s->ppc_irq_orgate), TYPE_OR_IRQ,
&error_abort, NULL);
@@ -154,8 +171,6 @@ static void iotkit_init(Object *obj)
TYPE_SPLIT_IRQ, &error_abort, NULL);
g_free(name);
}
sysbus_init_child_obj(obj, "s32ktimer", &s->s32ktimer, sizeof(s->s32ktimer),
TYPE_UNIMPLEMENTED_DEVICE);
}
static void iotkit_exp_irq(void *opaque, int n, int level)
@@ -390,13 +405,15 @@ static void iotkit_realize(DeviceState *dev, Error **errp)
return;
}
qdev_prop_set_string(DEVICE(&s->dualtimer), "name", "Dual timer");
qdev_prop_set_uint64(DEVICE(&s->dualtimer), "size", 0x1000);
qdev_prop_set_uint32(DEVICE(&s->dualtimer), "pclk-frq", s->mainclk_frq);
object_property_set_bool(OBJECT(&s->dualtimer), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
sysbus_connect_irq(SYS_BUS_DEVICE(&s->dualtimer), 0,
qdev_get_gpio_in(DEVICE(&s->armv7m), 5));
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dualtimer), 0);
object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[2]", &err);
if (err) {
@@ -462,13 +479,14 @@ static void iotkit_realize(DeviceState *dev, Error **errp)
/* Devices behind APB PPC1:
* 0x4002f000: S32K timer
*/
qdev_prop_set_string(DEVICE(&s->s32ktimer), "name", "S32KTIMER");
qdev_prop_set_uint64(DEVICE(&s->s32ktimer), "size", 0x1000);
qdev_prop_set_uint32(DEVICE(&s->s32ktimer), "pclk-frq", S32KCLK);
object_property_set_bool(OBJECT(&s->s32ktimer), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
sysbus_connect_irq(SYS_BUS_DEVICE(&s->s32ktimer), 0,
qdev_get_gpio_in(DEVICE(&s->armv7m), 2));
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->s32ktimer), 0);
object_property_set_link(OBJECT(&s->apb_ppc1), OBJECT(mr), "port[0]", &err);
if (err) {
@@ -501,19 +519,66 @@ static void iotkit_realize(DeviceState *dev, Error **errp)
qdev_get_gpio_in_named(dev_apb_ppc1,
"cfg_sec_resp", 0));
/* Using create_unimplemented_device() maps the stub into the
* system address space rather than into our container, but the
* overall effect to the guest is the same.
*/
create_unimplemented_device("SYSINFO", 0x40020000, 0x1000);
object_property_set_bool(OBJECT(&s->sysinfo), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
/* System information registers */
sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysinfo), 0, 0x40020000);
/* System control registers */
object_property_set_bool(OBJECT(&s->sysctl), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysctl), 0, 0x50021000);
create_unimplemented_device("SYSCONTROL", 0x50021000, 0x1000);
create_unimplemented_device("S32KWATCHDOG", 0x5002e000, 0x1000);
/* This OR gate wires together outputs from the secure watchdogs to NMI */
object_property_set_int(OBJECT(&s->nmi_orgate), 2, "num-lines", &err);
if (err) {
error_propagate(errp, err);
return;
}
object_property_set_bool(OBJECT(&s->nmi_orgate), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
qdev_connect_gpio_out(DEVICE(&s->nmi_orgate), 0,
qdev_get_gpio_in_named(DEVICE(&s->armv7m), "NMI", 0));
qdev_prop_set_uint32(DEVICE(&s->s32kwatchdog), "wdogclk-frq", S32KCLK);
object_property_set_bool(OBJECT(&s->s32kwatchdog), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
sysbus_connect_irq(SYS_BUS_DEVICE(&s->s32kwatchdog), 0,
qdev_get_gpio_in(DEVICE(&s->nmi_orgate), 0));
sysbus_mmio_map(SYS_BUS_DEVICE(&s->s32kwatchdog), 0, 0x5002e000);
/* 0x40080000 .. 0x4008ffff : IoTKit second Base peripheral region */
create_unimplemented_device("NS watchdog", 0x40081000, 0x1000);
create_unimplemented_device("S watchdog", 0x50081000, 0x1000);
qdev_prop_set_uint32(DEVICE(&s->nswatchdog), "wdogclk-frq", s->mainclk_frq);
object_property_set_bool(OBJECT(&s->nswatchdog), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
sysbus_connect_irq(SYS_BUS_DEVICE(&s->nswatchdog), 0,
qdev_get_gpio_in(DEVICE(&s->armv7m), 1));
sysbus_mmio_map(SYS_BUS_DEVICE(&s->nswatchdog), 0, 0x40081000);
qdev_prop_set_uint32(DEVICE(&s->swatchdog), "wdogclk-frq", s->mainclk_frq);
object_property_set_bool(OBJECT(&s->swatchdog), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
sysbus_connect_irq(SYS_BUS_DEVICE(&s->swatchdog), 0,
qdev_get_gpio_in(DEVICE(&s->nmi_orgate), 1));
sysbus_mmio_map(SYS_BUS_DEVICE(&s->swatchdog), 0, 0x50081000);
for (i = 0; i < ARRAY_SIZE(s->ppc_irq_splitter); i++) {
Object *splitter = OBJECT(&s->ppc_irq_splitter[i]);
@@ -602,6 +667,21 @@ static void iotkit_realize(DeviceState *dev, Error **errp)
iotkit_forward_sec_resp_cfg(s);
/* Forward the MSC related signals */
qdev_pass_gpios(dev_secctl, dev, "mscexp_status");
qdev_pass_gpios(dev_secctl, dev, "mscexp_clear");
qdev_pass_gpios(dev_secctl, dev, "mscexp_ns");
qdev_connect_gpio_out_named(dev_secctl, "msc_irq", 0,
qdev_get_gpio_in(DEVICE(&s->armv7m), 11));
/*
* Expose our container region to the board model; this corresponds
* to the AHB Slave Expansion ports which allow bus master devices
* (eg DMA controllers) in the board model to make transactions into
* devices in the IoTKit.
*/
sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->container);
system_clock_scale = NANOSECONDS_PER_SECOND / s->mainclk_frq;
}
+127 -15
View File
@@ -45,7 +45,10 @@
#include "hw/misc/mps2-scc.h"
#include "hw/misc/mps2-fpgaio.h"
#include "hw/misc/tz-mpc.h"
#include "hw/misc/tz-msc.h"
#include "hw/arm/iotkit.h"
#include "hw/dma/pl080.h"
#include "hw/ssi/pl022.h"
#include "hw/devices.h"
#include "net/net.h"
#include "hw/core/split-irq.h"
@@ -71,12 +74,13 @@ typedef struct {
MPS2FPGAIO fpgaio;
TZPPC ppc[5];
TZMPC ssram_mpc[3];
UnimplementedDeviceState spi[5];
PL022State spi[5];
UnimplementedDeviceState i2c[4];
UnimplementedDeviceState i2s_audio;
UnimplementedDeviceState gpio[4];
UnimplementedDeviceState dma[4];
UnimplementedDeviceState gfx;
PL080State dma[4];
TZMSC msc[4];
CMSDKAPBUART uart[5];
SplitIRQ sec_resp_splitter;
qemu_or_irq uart_irq_orgate;
@@ -188,7 +192,7 @@ static MemoryRegion *make_scc(MPS2TZMachineState *mms, void *opaque,
sccdev = DEVICE(scc);
qdev_set_parent_bus(sccdev, sysbus_get_default());
qdev_prop_set_uint32(sccdev, "scc-cfg4", 0x2);
qdev_prop_set_uint32(sccdev, "scc-aid", 0x02000008);
qdev_prop_set_uint32(sccdev, "scc-aid", 0x00200008);
qdev_prop_set_uint32(sccdev, "scc-id", mmc->scc_id);
object_property_set_bool(OBJECT(scc), true, "realized", &error_fatal);
return sysbus_mmio_get_region(SYS_BUS_DEVICE(sccdev), 0);
@@ -263,6 +267,89 @@ static MemoryRegion *make_mpc(MPS2TZMachineState *mms, void *opaque,
return sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 0);
}
static MemoryRegion *make_dma(MPS2TZMachineState *mms, void *opaque,
const char *name, hwaddr size)
{
PL080State *dma = opaque;
int i = dma - &mms->dma[0];
SysBusDevice *s;
char *mscname = g_strdup_printf("%s-msc", name);
TZMSC *msc = &mms->msc[i];
DeviceState *iotkitdev = DEVICE(&mms->iotkit);
MemoryRegion *msc_upstream;
MemoryRegion *msc_downstream;
/*
* Each DMA device is a PL081 whose transaction master interface
* is guarded by a Master Security Controller. The downstream end of
* the MSC connects to the IoTKit AHB Slave Expansion port, so the
* DMA devices can see all devices and memory that the CPU does.
*/
sysbus_init_child_obj(OBJECT(mms), mscname, msc, sizeof(*msc), TYPE_TZ_MSC);
msc_downstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(&mms->iotkit), 0);
object_property_set_link(OBJECT(msc), OBJECT(msc_downstream),
"downstream", &error_fatal);
object_property_set_link(OBJECT(msc), OBJECT(mms),
"idau", &error_fatal);
object_property_set_bool(OBJECT(msc), true, "realized", &error_fatal);
qdev_connect_gpio_out_named(DEVICE(msc), "irq", 0,
qdev_get_gpio_in_named(iotkitdev,
"mscexp_status", i));
qdev_connect_gpio_out_named(iotkitdev, "mscexp_clear", i,
qdev_get_gpio_in_named(DEVICE(msc),
"irq_clear", 0));
qdev_connect_gpio_out_named(iotkitdev, "mscexp_ns", i,
qdev_get_gpio_in_named(DEVICE(msc),
"cfg_nonsec", 0));
qdev_connect_gpio_out(DEVICE(&mms->sec_resp_splitter),
ARRAY_SIZE(mms->ppc) + i,
qdev_get_gpio_in_named(DEVICE(msc),
"cfg_sec_resp", 0));
msc_upstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(msc), 0);
sysbus_init_child_obj(OBJECT(mms), name, dma, sizeof(*dma), TYPE_PL081);
object_property_set_link(OBJECT(dma), OBJECT(msc_upstream),
"downstream", &error_fatal);
object_property_set_bool(OBJECT(dma), true, "realized", &error_fatal);
s = SYS_BUS_DEVICE(dma);
/* Wire up DMACINTR, DMACINTERR, DMACINTTC */
sysbus_connect_irq(s, 0, qdev_get_gpio_in_named(iotkitdev,
"EXP_IRQ", 58 + i * 3));
sysbus_connect_irq(s, 1, qdev_get_gpio_in_named(iotkitdev,
"EXP_IRQ", 56 + i * 3));
sysbus_connect_irq(s, 2, qdev_get_gpio_in_named(iotkitdev,
"EXP_IRQ", 57 + i * 3));
return sysbus_mmio_get_region(s, 0);
}
static MemoryRegion *make_spi(MPS2TZMachineState *mms, void *opaque,
const char *name, hwaddr size)
{
/*
* The AN505 has five PL022 SPI controllers.
* One of these should have the LCD controller behind it; the others
* are connected only to the FPGA's "general purpose SPI connector"
* or "shield" expansion connectors.
* Note that if we do implement devices behind SPI, the chip select
* lines are set via the "MISC" register in the MPS2 FPGAIO device.
*/
PL022State *spi = opaque;
int i = spi - &mms->spi[0];
DeviceState *iotkitdev = DEVICE(&mms->iotkit);
SysBusDevice *s;
sysbus_init_child_obj(OBJECT(mms), name, spi, sizeof(mms->spi[0]),
TYPE_PL022);
object_property_set_bool(OBJECT(spi), true, "realized", &error_fatal);
s = SYS_BUS_DEVICE(spi);
sysbus_connect_irq(s, 0,
qdev_get_gpio_in_named(iotkitdev, "EXP_IRQ", 51 + i));
return sysbus_mmio_get_region(s, 0);
}
static void mps2tz_common_init(MachineState *machine)
{
MPS2TZMachineState *mms = MPS2TZ_MACHINE(machine);
@@ -289,13 +376,14 @@ static void mps2tz_common_init(MachineState *machine)
&error_fatal);
/* The sec_resp_cfg output from the IoTKit must be split into multiple
* lines, one for each of the PPCs we create here.
* lines, one for each of the PPCs we create here, plus one per MSC.
*/
object_initialize(&mms->sec_resp_splitter, sizeof(mms->sec_resp_splitter),
TYPE_SPLIT_IRQ);
object_property_add_child(OBJECT(machine), "sec-resp-splitter",
OBJECT(&mms->sec_resp_splitter), &error_abort);
object_property_set_int(OBJECT(&mms->sec_resp_splitter), 5,
object_property_set_int(OBJECT(&mms->sec_resp_splitter),
ARRAY_SIZE(mms->ppc) + ARRAY_SIZE(mms->msc),
"num-lines", &error_fatal);
object_property_set_bool(OBJECT(&mms->sec_resp_splitter), true,
"realized", &error_fatal);
@@ -360,11 +448,11 @@ static void mps2tz_common_init(MachineState *machine)
}, {
.name = "apb_ppcexp1",
.ports = {
{ "spi0", make_unimp_dev, &mms->spi[0], 0x40205000, 0x1000 },
{ "spi1", make_unimp_dev, &mms->spi[1], 0x40206000, 0x1000 },
{ "spi2", make_unimp_dev, &mms->spi[2], 0x40209000, 0x1000 },
{ "spi3", make_unimp_dev, &mms->spi[3], 0x4020a000, 0x1000 },
{ "spi4", make_unimp_dev, &mms->spi[4], 0x4020b000, 0x1000 },
{ "spi0", make_spi, &mms->spi[0], 0x40205000, 0x1000 },
{ "spi1", make_spi, &mms->spi[1], 0x40206000, 0x1000 },
{ "spi2", make_spi, &mms->spi[2], 0x40209000, 0x1000 },
{ "spi3", make_spi, &mms->spi[3], 0x4020a000, 0x1000 },
{ "spi4", make_spi, &mms->spi[4], 0x4020b000, 0x1000 },
{ "uart0", make_uart, &mms->uart[0], 0x40200000, 0x1000 },
{ "uart1", make_uart, &mms->uart[1], 0x40201000, 0x1000 },
{ "uart2", make_uart, &mms->uart[2], 0x40202000, 0x1000 },
@@ -396,10 +484,10 @@ static void mps2tz_common_init(MachineState *machine)
}, {
.name = "ahb_ppcexp1",
.ports = {
{ "dma0", make_unimp_dev, &mms->dma[0], 0x40110000, 0x1000 },
{ "dma1", make_unimp_dev, &mms->dma[1], 0x40111000, 0x1000 },
{ "dma2", make_unimp_dev, &mms->dma[2], 0x40112000, 0x1000 },
{ "dma3", make_unimp_dev, &mms->dma[3], 0x40113000, 0x1000 },
{ "dma0", make_dma, &mms->dma[0], 0x40110000, 0x1000 },
{ "dma1", make_dma, &mms->dma[1], 0x40111000, 0x1000 },
{ "dma2", make_dma, &mms->dma[2], 0x40112000, 0x1000 },
{ "dma3", make_dma, &mms->dma[3], 0x40113000, 0x1000 },
},
},
};
@@ -480,12 +568,32 @@ static void mps2tz_common_init(MachineState *machine)
armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, 0x400000);
}
static void mps2_tz_idau_check(IDAUInterface *ii, uint32_t address,
int *iregion, bool *exempt, bool *ns, bool *nsc)
{
/*
* The MPS2 TZ FPGA images have IDAUs in them which are connected to
* the Master Security Controllers. Thes have the same logic as
* is used by the IoTKit for the IDAU connected to the CPU, except
* that MSCs don't care about the NSC attribute.
*/
int region = extract32(address, 28, 4);
*ns = !(region & 1);
*nsc = false;
/* 0xe0000000..0xe00fffff and 0xf0000000..0xf00fffff are exempt */
*exempt = (address & 0xeff00000) == 0xe0000000;
*iregion = region;
}
static void mps2tz_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
IDAUInterfaceClass *iic = IDAU_INTERFACE_CLASS(oc);
mc->init = mps2tz_common_init;
mc->max_cpus = 1;
iic->check = mps2_tz_idau_check;
}
static void mps2tz_an505_class_init(ObjectClass *oc, void *data)
@@ -496,7 +604,7 @@ static void mps2tz_an505_class_init(ObjectClass *oc, void *data)
mc->desc = "ARM MPS2 with AN505 FPGA image for Cortex-M33";
mmc->fpga_type = FPGA_AN505;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m33");
mmc->scc_id = 0x41040000 | (505 << 4);
mmc->scc_id = 0x41045050;
}
static const TypeInfo mps2tz_info = {
@@ -506,6 +614,10 @@ static const TypeInfo mps2tz_info = {
.instance_size = sizeof(MPS2TZMachineState),
.class_size = sizeof(MPS2TZMachineClass),
.class_init = mps2tz_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_IDAU_INTERFACE },
{ }
},
};
static const TypeInfo mps2tz_an505_info = {
+14 -3
View File
@@ -34,6 +34,7 @@
#include "hw/misc/unimp.h"
#include "hw/char/cmsdk-apb-uart.h"
#include "hw/timer/cmsdk-apb-timer.h"
#include "hw/timer/cmsdk-apb-dualtimer.h"
#include "hw/misc/mps2-scc.h"
#include "hw/devices.h"
#include "net/net.h"
@@ -64,6 +65,7 @@ typedef struct {
MemoryRegion blockram_m3;
MemoryRegion sram;
MPS2SCC scc;
CMSDKAPBDualTimer dualtimer;
} MPS2MachineState;
#define TYPE_MPS2_MACHINE "mps2"
@@ -297,11 +299,20 @@ static void mps2_common_init(MachineState *machine)
cmsdk_apb_timer_create(0x40000000, qdev_get_gpio_in(armv7m, 8), SYSCLK_FRQ);
cmsdk_apb_timer_create(0x40001000, qdev_get_gpio_in(armv7m, 9), SYSCLK_FRQ);
sysbus_init_child_obj(OBJECT(mms), "dualtimer", &mms->dualtimer,
sizeof(mms->dualtimer), TYPE_CMSDK_APB_DUALTIMER);
qdev_prop_set_uint32(DEVICE(&mms->dualtimer), "pclk-frq", SYSCLK_FRQ);
object_property_set_bool(OBJECT(&mms->dualtimer), true, "realized",
&error_fatal);
sysbus_connect_irq(SYS_BUS_DEVICE(&mms->dualtimer), 0,
qdev_get_gpio_in(armv7m, 10));
sysbus_mmio_map(SYS_BUS_DEVICE(&mms->dualtimer), 0, 0x40002000);
object_initialize(&mms->scc, sizeof(mms->scc), TYPE_MPS2_SCC);
sccdev = DEVICE(&mms->scc);
qdev_set_parent_bus(sccdev, sysbus_get_default());
qdev_prop_set_uint32(sccdev, "scc-cfg4", 0x2);
qdev_prop_set_uint32(sccdev, "scc-aid", 0x02000008);
qdev_prop_set_uint32(sccdev, "scc-aid", 0x00200008);
qdev_prop_set_uint32(sccdev, "scc-id", mmc->scc_id);
object_property_set_bool(OBJECT(&mms->scc), true, "realized",
&error_fatal);
@@ -336,7 +347,7 @@ static void mps2_an385_class_init(ObjectClass *oc, void *data)
mc->desc = "ARM MPS2 with AN385 FPGA image for Cortex-M3";
mmc->fpga_type = FPGA_AN385;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m3");
mmc->scc_id = 0x41040000 | (385 << 4);
mmc->scc_id = 0x41043850;
}
static void mps2_an511_class_init(ObjectClass *oc, void *data)
@@ -347,7 +358,7 @@ static void mps2_an511_class_init(ObjectClass *oc, void *data)
mc->desc = "ARM MPS2 with AN511 DesignStart FPGA image for Cortex-M3";
mmc->fpga_type = FPGA_AN511;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m3");
mmc->scc_id = 0x4104000 | (511 << 4);
mmc->scc_id = 0x41045110;
}
static const TypeInfo mps2_info = {
+59 -5
View File
@@ -172,6 +172,7 @@ typedef struct {
typedef struct {
MachineState parent;
bool secure;
bool virt;
} VexpressMachineState;
#define TYPE_VEXPRESS_MACHINE "vexpress"
@@ -203,7 +204,7 @@ struct VEDBoardInfo {
};
static void init_cpus(const char *cpu_type, const char *privdev,
hwaddr periphbase, qemu_irq *pic, bool secure)
hwaddr periphbase, qemu_irq *pic, bool secure, bool virt)
{
DeviceState *dev;
SysBusDevice *busdev;
@@ -216,6 +217,11 @@ static void init_cpus(const char *cpu_type, const char *privdev,
if (!secure) {
object_property_set_bool(cpuobj, false, "has_el3", NULL);
}
if (!virt) {
if (object_property_find(cpuobj, "has_el2", NULL)) {
object_property_set_bool(cpuobj, false, "has_el2", NULL);
}
}
if (object_property_find(cpuobj, "reset-cbar", NULL)) {
object_property_set_int(cpuobj, periphbase,
@@ -251,6 +257,10 @@ static void init_cpus(const char *cpu_type, const char *privdev,
sysbus_connect_irq(busdev, n, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
sysbus_connect_irq(busdev, n + smp_cpus,
qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
sysbus_connect_irq(busdev, n + 2 * smp_cpus,
qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
sysbus_connect_irq(busdev, n + 3 * smp_cpus,
qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
}
}
@@ -285,7 +295,8 @@ static void a9_daughterboard_init(const VexpressMachineState *vms,
memory_region_add_subregion(sysmem, 0x60000000, ram);
/* 0x1e000000 A9MPCore (SCU) private memory region */
init_cpus(cpu_type, TYPE_A9MPCORE_PRIV, 0x1e000000, pic, vms->secure);
init_cpus(cpu_type, TYPE_A9MPCORE_PRIV, 0x1e000000, pic,
vms->secure, vms->virt);
/* Daughterboard peripherals : 0x10020000 .. 0x20000000 */
@@ -366,7 +377,8 @@ static void a15_daughterboard_init(const VexpressMachineState *vms,
memory_region_add_subregion(sysmem, 0x80000000, ram);
/* 0x2c000000 A15MPCore private memory region (GIC) */
init_cpus(cpu_type, TYPE_A15MPCORE_PRIV, 0x2c000000, pic, vms->secure);
init_cpus(cpu_type, TYPE_A15MPCORE_PRIV, 0x2c000000, pic, vms->secure,
vms->virt);
/* A15 daughterboard peripherals: */
@@ -701,8 +713,8 @@ static void vexpress_common_init(MachineState *machine)
daughterboard->bootinfo.smp_bootreg_addr = map[VE_SYSREGS] + 0x30;
daughterboard->bootinfo.gic_cpu_if_addr = daughterboard->gic_cpu_if_addr;
daughterboard->bootinfo.modify_dtb = vexpress_modify_dtb;
/* Indicate that when booting Linux we should be in secure state */
daughterboard->bootinfo.secure_boot = true;
/* When booting Linux we should be in secure state if the CPU has one. */
daughterboard->bootinfo.secure_boot = vms->secure;
arm_load_kernel(ARM_CPU(first_cpu), &daughterboard->bootinfo);
}
@@ -720,6 +732,20 @@ static void vexpress_set_secure(Object *obj, bool value, Error **errp)
vms->secure = value;
}
static bool vexpress_get_virt(Object *obj, Error **errp)
{
VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
return vms->virt;
}
static void vexpress_set_virt(Object *obj, bool value, Error **errp)
{
VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
vms->virt = value;
}
static void vexpress_instance_init(Object *obj)
{
VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
@@ -734,6 +760,32 @@ static void vexpress_instance_init(Object *obj)
NULL);
}
static void vexpress_a15_instance_init(Object *obj)
{
VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
/*
* For the vexpress-a15, EL2 is by default enabled if EL3 is,
* but can also be specifically set to on or off.
*/
vms->virt = true;
object_property_add_bool(obj, "virtualization", vexpress_get_virt,
vexpress_set_virt, NULL);
object_property_set_description(obj, "virtualization",
"Set on/off to enable/disable the ARM "
"Virtualization Extensions "
"(defaults to same as 'secure')",
NULL);
}
static void vexpress_a9_instance_init(Object *obj)
{
VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
/* The A9 doesn't have the virt extensions */
vms->virt = false;
}
static void vexpress_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -780,12 +832,14 @@ static const TypeInfo vexpress_a9_info = {
.name = TYPE_VEXPRESS_A9_MACHINE,
.parent = TYPE_VEXPRESS_MACHINE,
.class_init = vexpress_a9_class_init,
.instance_init = vexpress_a9_instance_init,
};
static const TypeInfo vexpress_a15_info = {
.name = TYPE_VEXPRESS_A15_MACHINE,
.parent = TYPE_VEXPRESS_MACHINE,
.class_init = vexpress_a15_class_init,
.instance_init = vexpress_a15_instance_init,
};
static void vexpress_machine_init(void)
+28 -3
View File
@@ -53,6 +53,7 @@ static void a15mp_priv_realize(DeviceState *dev, Error **errp)
int i;
Error *err = NULL;
bool has_el3;
bool has_el2 = false;
Object *cpuobj;
gicdev = DEVICE(&s->gic);
@@ -67,6 +68,10 @@ static void a15mp_priv_realize(DeviceState *dev, Error **errp)
has_el3 = object_property_find(cpuobj, "has_el3", NULL) &&
object_property_get_bool(cpuobj, "has_el3", &error_abort);
qdev_prop_set_bit(gicdev, "has-security-extensions", has_el3);
/* Similarly for virtualization support */
has_el2 = object_property_find(cpuobj, "has_el2", NULL) &&
object_property_get_bool(cpuobj, "has_el2", &error_abort);
qdev_prop_set_bit(gicdev, "has-virtualization-extensions", has_el2);
}
object_property_set_bool(OBJECT(&s->gic), true, "realized", &err);
@@ -103,20 +108,40 @@ static void a15mp_priv_realize(DeviceState *dev, Error **errp)
qdev_get_gpio_in(gicdev,
ppibase + timer_irq[irq]));
}
if (has_el2) {
/* Connect the GIC maintenance interrupt to PPI ID 25 */
sysbus_connect_irq(SYS_BUS_DEVICE(gicdev), i + 4 * s->num_cpu,
qdev_get_gpio_in(gicdev, ppibase + 25));
}
}
/* Memory map (addresses are offsets from PERIPHBASE):
* 0x0000-0x0fff -- reserved
* 0x1000-0x1fff -- GIC Distributor
* 0x2000-0x3fff -- GIC CPU interface
* 0x4000-0x4fff -- GIC virtual interface control (not modelled)
* 0x5000-0x5fff -- GIC virtual interface control (not modelled)
* 0x6000-0x7fff -- GIC virtual CPU interface (not modelled)
* 0x4000-0x4fff -- GIC virtual interface control for this CPU
* 0x5000-0x51ff -- GIC virtual interface control for CPU 0
* 0x5200-0x53ff -- GIC virtual interface control for CPU 1
* 0x5400-0x55ff -- GIC virtual interface control for CPU 2
* 0x5600-0x57ff -- GIC virtual interface control for CPU 3
* 0x6000-0x7fff -- GIC virtual CPU interface
*/
memory_region_add_subregion(&s->container, 0x1000,
sysbus_mmio_get_region(busdev, 0));
memory_region_add_subregion(&s->container, 0x2000,
sysbus_mmio_get_region(busdev, 1));
if (has_el2) {
memory_region_add_subregion(&s->container, 0x4000,
sysbus_mmio_get_region(busdev, 2));
memory_region_add_subregion(&s->container, 0x6000,
sysbus_mmio_get_region(busdev, 3));
for (i = 0; i < s->num_cpu; i++) {
hwaddr base = 0x5000 + i * 0x200;
MemoryRegion *mr = sysbus_mmio_get_region(busdev,
4 + s->num_cpu + i);
memory_region_add_subregion(&s->container, base, mr);
}
}
}
static Property a15mp_priv_properties[] = {
+130 -88
View File
@@ -34,6 +34,13 @@
#define DEFAULT_VCRAM_SIZE 0x4000000
#define BCM2835_FB_OFFSET 0x00100000
/* Maximum permitted framebuffer size; experimentally determined on an rpi2 */
#define XRES_MAX 3840
#define YRES_MAX 2560
/* Framebuffer size used if guest requests zero size */
#define XRES_SMALL 592
#define YRES_SMALL 488
static void fb_invalidate_display(void *opaque)
{
BCM2835FBState *s = BCM2835_FB(opaque);
@@ -52,7 +59,7 @@ static void draw_line_src16(void *opaque, uint8_t *dst, const uint8_t *src,
int bpp = surface_bits_per_pixel(surface);
while (width--) {
switch (s->bpp) {
switch (s->config.bpp) {
case 8:
/* lookup palette starting at video ram base
* TODO: cache translation, rather than doing this each time!
@@ -91,7 +98,7 @@ static void draw_line_src16(void *opaque, uint8_t *dst, const uint8_t *src,
break;
}
if (s->pixo == 0) {
if (s->config.pixo == 0) {
/* swap to BGR pixel format */
uint8_t tmp = r;
r = b;
@@ -126,6 +133,18 @@ static void draw_line_src16(void *opaque, uint8_t *dst, const uint8_t *src,
}
}
static bool fb_use_offsets(BCM2835FBConfig *config)
{
/*
* Return true if we should use the viewport offsets.
* Experimentally, the hardware seems to do this only if the
* viewport size is larger than the physical screen. (It doesn't
* prevent the guest setting this silly viewport setting, though...)
*/
return config->xres_virtual > config->xres &&
config->yres_virtual > config->yres;
}
static void fb_update_display(void *opaque)
{
BCM2835FBState *s = opaque;
@@ -134,13 +153,19 @@ static void fb_update_display(void *opaque)
int last = 0;
int src_width = 0;
int dest_width = 0;
uint32_t xoff = 0, yoff = 0;
if (s->lock || !s->xres) {
if (s->lock || !s->config.xres) {
return;
}
src_width = s->xres * (s->bpp >> 3);
dest_width = s->xres;
src_width = bcm2835_fb_get_pitch(&s->config);
if (fb_use_offsets(&s->config)) {
xoff = s->config.xoffset;
yoff = s->config.yoffset;
}
dest_width = s->config.xres;
switch (surface_bits_per_pixel(surface)) {
case 0:
@@ -165,89 +190,104 @@ static void fb_update_display(void *opaque)
}
if (s->invalidate) {
framebuffer_update_memory_section(&s->fbsection, s->dma_mr, s->base,
s->yres, src_width);
hwaddr base = s->config.base + xoff + yoff * src_width;
framebuffer_update_memory_section(&s->fbsection, s->dma_mr,
base,
s->config.yres, src_width);
}
framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
framebuffer_update_display(surface, &s->fbsection,
s->config.xres, s->config.yres,
src_width, dest_width, 0, s->invalidate,
draw_line_src16, s, &first, &last);
if (first >= 0) {
dpy_gfx_update(s->con, 0, first, s->xres, last - first + 1);
dpy_gfx_update(s->con, 0, first, s->config.xres,
last - first + 1);
}
s->invalidate = false;
}
static void bcm2835_fb_mbox_push(BCM2835FBState *s, uint32_t value)
void bcm2835_fb_validate_config(BCM2835FBConfig *config)
{
value &= ~0xf;
/*
* Validate the config, and clip any bogus values into range,
* as the hardware does. Note that fb_update_display() relies on
* this happening to prevent it from performing out-of-range
* accesses on redraw.
*/
config->xres = MIN(config->xres, XRES_MAX);
config->xres_virtual = MIN(config->xres_virtual, XRES_MAX);
config->yres = MIN(config->yres, YRES_MAX);
config->yres_virtual = MIN(config->yres_virtual, YRES_MAX);
/*
* These are not minima: a 40x40 framebuffer will be accepted.
* They're only used as defaults if the guest asks for zero size.
*/
if (config->xres == 0) {
config->xres = XRES_SMALL;
}
if (config->yres == 0) {
config->yres = YRES_SMALL;
}
if (config->xres_virtual == 0) {
config->xres_virtual = config->xres;
}
if (config->yres_virtual == 0) {
config->yres_virtual = config->yres;
}
if (fb_use_offsets(config)) {
/* Clip the offsets so the viewport is within the physical screen */
config->xoffset = MIN(config->xoffset,
config->xres_virtual - config->xres);
config->yoffset = MIN(config->yoffset,
config->yres_virtual - config->yres);
}
}
void bcm2835_fb_reconfigure(BCM2835FBState *s, BCM2835FBConfig *newconfig)
{
s->lock = true;
s->xres = ldl_le_phys(&s->dma_as, value);
s->yres = ldl_le_phys(&s->dma_as, value + 4);
s->xres_virtual = ldl_le_phys(&s->dma_as, value + 8);
s->yres_virtual = ldl_le_phys(&s->dma_as, value + 12);
s->bpp = ldl_le_phys(&s->dma_as, value + 20);
s->xoffset = ldl_le_phys(&s->dma_as, value + 24);
s->yoffset = ldl_le_phys(&s->dma_as, value + 28);
s->base = s->vcram_base | (value & 0xc0000000);
s->base += BCM2835_FB_OFFSET;
/* TODO - Manage properly virtual resolution */
s->pitch = s->xres * (s->bpp >> 3);
s->size = s->yres * s->pitch;
stl_le_phys(&s->dma_as, value + 16, s->pitch);
stl_le_phys(&s->dma_as, value + 32, s->base);
stl_le_phys(&s->dma_as, value + 36, s->size);
s->config = *newconfig;
s->invalidate = true;
qemu_console_resize(s->con, s->xres, s->yres);
qemu_console_resize(s->con, s->config.xres, s->config.yres);
s->lock = false;
}
void bcm2835_fb_reconfigure(BCM2835FBState *s, uint32_t *xres, uint32_t *yres,
uint32_t *xoffset, uint32_t *yoffset, uint32_t *bpp,
uint32_t *pixo, uint32_t *alpha)
static void bcm2835_fb_mbox_push(BCM2835FBState *s, uint32_t value)
{
s->lock = true;
uint32_t pitch;
uint32_t size;
BCM2835FBConfig newconf;
/* TODO: input validation! */
if (xres) {
s->xres = *xres;
}
if (yres) {
s->yres = *yres;
}
if (xoffset) {
s->xoffset = *xoffset;
}
if (yoffset) {
s->yoffset = *yoffset;
}
if (bpp) {
s->bpp = *bpp;
}
if (pixo) {
s->pixo = *pixo;
}
if (alpha) {
s->alpha = *alpha;
}
value &= ~0xf;
/* TODO - Manage properly virtual resolution */
newconf.xres = ldl_le_phys(&s->dma_as, value);
newconf.yres = ldl_le_phys(&s->dma_as, value + 4);
newconf.xres_virtual = ldl_le_phys(&s->dma_as, value + 8);
newconf.yres_virtual = ldl_le_phys(&s->dma_as, value + 12);
newconf.bpp = ldl_le_phys(&s->dma_as, value + 20);
newconf.xoffset = ldl_le_phys(&s->dma_as, value + 24);
newconf.yoffset = ldl_le_phys(&s->dma_as, value + 28);
s->pitch = s->xres * (s->bpp >> 3);
s->size = s->yres * s->pitch;
newconf.base = s->vcram_base | (value & 0xc0000000);
newconf.base += BCM2835_FB_OFFSET;
s->invalidate = true;
qemu_console_resize(s->con, s->xres, s->yres);
s->lock = false;
bcm2835_fb_validate_config(&newconf);
pitch = bcm2835_fb_get_pitch(&newconf);
size = bcm2835_fb_get_size(&newconf);
stl_le_phys(&s->dma_as, value + 16, pitch);
stl_le_phys(&s->dma_as, value + 32, newconf.base);
stl_le_phys(&s->dma_as, value + 36, size);
bcm2835_fb_reconfigure(s, &newconf);
}
static uint64_t bcm2835_fb_read(void *opaque, hwaddr offset, unsigned size)
@@ -312,18 +352,17 @@ static const VMStateDescription vmstate_bcm2835_fb = {
VMSTATE_BOOL(lock, BCM2835FBState),
VMSTATE_BOOL(invalidate, BCM2835FBState),
VMSTATE_BOOL(pending, BCM2835FBState),
VMSTATE_UINT32(xres, BCM2835FBState),
VMSTATE_UINT32(yres, BCM2835FBState),
VMSTATE_UINT32(xres_virtual, BCM2835FBState),
VMSTATE_UINT32(yres_virtual, BCM2835FBState),
VMSTATE_UINT32(xoffset, BCM2835FBState),
VMSTATE_UINT32(yoffset, BCM2835FBState),
VMSTATE_UINT32(bpp, BCM2835FBState),
VMSTATE_UINT32(base, BCM2835FBState),
VMSTATE_UINT32(pitch, BCM2835FBState),
VMSTATE_UINT32(size, BCM2835FBState),
VMSTATE_UINT32(pixo, BCM2835FBState),
VMSTATE_UINT32(alpha, BCM2835FBState),
VMSTATE_UINT32(config.xres, BCM2835FBState),
VMSTATE_UINT32(config.yres, BCM2835FBState),
VMSTATE_UINT32(config.xres_virtual, BCM2835FBState),
VMSTATE_UINT32(config.yres_virtual, BCM2835FBState),
VMSTATE_UINT32(config.xoffset, BCM2835FBState),
VMSTATE_UINT32(config.yoffset, BCM2835FBState),
VMSTATE_UINT32(config.bpp, BCM2835FBState),
VMSTATE_UINT32(config.base, BCM2835FBState),
VMSTATE_UNUSED(8), /* Was pitch and size */
VMSTATE_UINT32(config.pixo, BCM2835FBState),
VMSTATE_UINT32(config.alpha, BCM2835FBState),
VMSTATE_END_OF_LIST()
}
};
@@ -349,13 +388,7 @@ static void bcm2835_fb_reset(DeviceState *dev)
s->pending = false;
s->xres_virtual = s->xres;
s->yres_virtual = s->yres;
s->xoffset = 0;
s->yoffset = 0;
s->base = s->vcram_base + BCM2835_FB_OFFSET;
s->pitch = s->xres * (s->bpp >> 3);
s->size = s->yres * s->pitch;
s->config = s->initial_config;
s->invalidate = true;
s->lock = false;
@@ -379,24 +412,33 @@ static void bcm2835_fb_realize(DeviceState *dev, Error **errp)
return;
}
/* Fill in the parts of initial_config that are not set by QOM properties */
s->initial_config.xres_virtual = s->initial_config.xres;
s->initial_config.yres_virtual = s->initial_config.yres;
s->initial_config.xoffset = 0;
s->initial_config.yoffset = 0;
s->initial_config.base = s->vcram_base + BCM2835_FB_OFFSET;
s->dma_mr = MEMORY_REGION(obj);
address_space_init(&s->dma_as, s->dma_mr, NULL);
bcm2835_fb_reset(dev);
s->con = graphic_console_init(dev, 0, &vgafb_ops, s);
qemu_console_resize(s->con, s->xres, s->yres);
qemu_console_resize(s->con, s->config.xres, s->config.yres);
}
static Property bcm2835_fb_props[] = {
DEFINE_PROP_UINT32("vcram-base", BCM2835FBState, vcram_base, 0),/*required*/
DEFINE_PROP_UINT32("vcram-size", BCM2835FBState, vcram_size,
DEFAULT_VCRAM_SIZE),
DEFINE_PROP_UINT32("xres", BCM2835FBState, xres, 640),
DEFINE_PROP_UINT32("yres", BCM2835FBState, yres, 480),
DEFINE_PROP_UINT32("bpp", BCM2835FBState, bpp, 16),
DEFINE_PROP_UINT32("pixo", BCM2835FBState, pixo, 1), /* 1=RGB, 0=BGR */
DEFINE_PROP_UINT32("alpha", BCM2835FBState, alpha, 2), /* alpha ignored */
DEFINE_PROP_UINT32("xres", BCM2835FBState, initial_config.xres, 640),
DEFINE_PROP_UINT32("yres", BCM2835FBState, initial_config.yres, 480),
DEFINE_PROP_UINT32("bpp", BCM2835FBState, initial_config.bpp, 16),
DEFINE_PROP_UINT32("pixo", BCM2835FBState,
initial_config.pixo, 1), /* 1=RGB, 0=BGR */
DEFINE_PROP_UINT32("alpha", BCM2835FBState,
initial_config.alpha, 2), /* alpha ignored */
DEFINE_PROP_END_OF_LIST()
};
+1 -1
View File
@@ -2084,7 +2084,7 @@ static void arm_gic_realize(DeviceState *dev, Error **errp)
for (i = 0; i < s->num_cpu; i++) {
memory_region_init_io(&s->vifaceiomem[i + 1], OBJECT(s),
&gic_viface_ops, &s->backref[i],
"gic_viface", 0x1000);
"gic_viface", 0x200);
sysbus_init_mmio(sbd, &s->vifaceiomem[i + 1]);
}
}
+3
View File
@@ -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
+60 -63
View File
@@ -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 = &alpha;
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 */
+65 -8
View File
@@ -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
},
};
+261
View File
@@ -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);
+128
View File
@@ -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);
+143 -3
View File
@@ -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
}
};

Some files were not shown because too many files have changed in this diff Show More