Commit 9403bccf authored by Peter Maydell's avatar Peter Maydell
Browse files

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



target-arm queue:
 * add MHU and dual-core support to Musca boards
 * refactor some VFP insns to be gated by ID registers
 * Revert "arm: Allow system registers for KVM guests to be changed by QEMU code"
 * Implement ARMv8.2-FHM extension
 * Advertise JSCVT via HWCAP for linux-user

# gpg: Signature made Thu 28 Feb 2019 11:06:55 GMT
# gpg:                using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE
# gpg:                issuer "peter.maydell@linaro.org"
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate]
# gpg:                 aka "Peter Maydell <pmaydell@gmail.com>" [ultimate]
# gpg:                 aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate]
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83  15CF 3C25 25ED 1436 0CDE

* remotes/pmaydell/tags/pull-target-arm-20190228-1:
  linux-user: Enable HWCAP_ASIMDFHM, HWCAP_JSCVT
  target/arm: Enable ARMv8.2-FHM for -cpu max
  target/arm: Implement VFMAL and VFMSL for aarch32
  target/arm: Implement FMLAL and FMLSL for aarch64
  target/arm: Add helpers for FMLAL
  Revert "arm: Allow system registers for KVM guests to be changed by QEMU code"
  target/arm: Gate "miscellaneous FP" insns by ID register field
  target/arm: Use MVFR1 feature bits to gate A32/T32 FP16 instructions
  hw/arm/armsse: Unify init-svtor and cpuwait handling
  hw/arm/iotkit-sysctl: Implement CPUWAIT and INITSVTOR*
  hw/arm/iotkit-sysctl: Add SSE-200 registers
  hw/misc/iotkit-sysctl: Correct typo in INITSVTOR0 register name
  target/arm/arm-powerctl: Add new arm_set_cpu_on_and_reset()
  target/arm/cpu: Allow init-svtor property to be set after realize
  hw/arm/armsse: Wire up the MHUs
  hw/misc/armsse-mhu.c: Model the SSE-200 Message Handling Unit

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 21ee7686 1c9af3a9
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -633,6 +633,8 @@ F: hw/misc/iotkit-sysinfo.c
F: include/hw/misc/iotkit-sysinfo.h
F: hw/misc/armsse-cpuid.c
F: include/hw/misc/armsse-cpuid.h
F: hw/misc/armsse-mhu.c
F: include/hw/misc/armsse-mhu.h

Musca
M: Peter Maydell <peter.maydell@linaro.org>
+1 −0
Original line number Diff line number Diff line
@@ -119,6 +119,7 @@ CONFIG_IOTKIT_SECCTL=y
CONFIG_IOTKIT_SYSCTL=y
CONFIG_IOTKIT_SYSINFO=y
CONFIG_ARMSSE_CPUID=y
CONFIG_ARMSSE_MHU=y

CONFIG_VERSATILE=y
CONFIG_VERSATILE_PCI=y
+61 −26
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@

#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qemu/bitops.h"
#include "qapi/error.h"
#include "trace.h"
#include "hw/sysbus.h"
@@ -29,6 +30,7 @@ struct ARMSSEInfo {
    int sram_banks;
    int num_cpus;
    uint32_t sys_version;
    uint32_t cpuwait_rst;
    SysConfigFormat sys_config_format;
    bool has_mhus;
    bool has_ppus;
@@ -43,6 +45,7 @@ static const ARMSSEInfo armsse_variants[] = {
        .sram_banks = 1,
        .num_cpus = 1,
        .sys_version = 0x41743,
        .cpuwait_rst = 0,
        .sys_config_format = IoTKitFormat,
        .has_mhus = false,
        .has_ppus = false,
@@ -55,6 +58,7 @@ static const ARMSSEInfo armsse_variants[] = {
        .sram_banks = 4,
        .num_cpus = 2,
        .sys_version = 0x22041743,
        .cpuwait_rst = 2,
        .sys_config_format = SSE200Format,
        .has_mhus = true,
        .has_ppus = true,
@@ -282,9 +286,9 @@ static void armsse_init(Object *obj)
                          sizeof(s->sysinfo), TYPE_IOTKIT_SYSINFO);
    if (info->has_mhus) {
        sysbus_init_child_obj(obj, "mhu0", &s->mhu[0], sizeof(s->mhu[0]),
                              TYPE_UNIMPLEMENTED_DEVICE);
                              TYPE_ARMSSE_MHU);
        sysbus_init_child_obj(obj, "mhu1", &s->mhu[1], sizeof(s->mhu[1]),
                              TYPE_UNIMPLEMENTED_DEVICE);
                              TYPE_ARMSSE_MHU);
    }
    if (info->has_ppus) {
        for (i = 0; i < info->num_cpus; i++) {
@@ -495,30 +499,33 @@ static void armsse_realize(DeviceState *dev, Error **errp)

        qdev_prop_set_uint32(cpudev, "num-irq", s->exp_numirq + 32);
        /*
         * In real hardware the initial Secure VTOR is set from the INITSVTOR0
         * register in the IoT Kit System Control Register block, and the
         * initial value of that is in turn specifiable by the FPGA that
         * instantiates the IoT Kit. In QEMU we don't implement this wrinkle,
         * and simply set the CPU's init-svtor to the IoT Kit default value.
         * In SSE-200 the situation is similar, except that the default value
         * is a reset-time signal input. Typically a board using the SSE-200
         * will have a system control processor whose boot firmware initializes
         * the INITSVTOR* registers before powering up the CPUs in any case,
         * so the hardware's default value doesn't matter. QEMU doesn't emulate
         * In real hardware the initial Secure VTOR is set from the INITSVTOR*
         * registers in the IoT Kit System Control Register block. In QEMU
         * we set the initial value here, and also the reset value of the
         * sysctl register, from this object's QOM init-svtor property.
         * If the guest changes the INITSVTOR* registers at runtime then the
         * code in iotkit-sysctl.c will update the CPU init-svtor property
         * (which will then take effect on the next CPU warm-reset).
         *
         * Note that typically a board using the SSE-200 will have a system
         * control processor whose boot firmware initializes the INITSVTOR*
         * registers before powering up the CPUs. QEMU doesn't emulate
         * the control processor, so instead we behave in the way that the
         * firmware does. The initial value is configurable by the board code
         * to match whatever its firmware does.
         * firmware does: the initial value should be set by the board code
         * (using the init-svtor property on the ARMSSE object) to match
         * whatever its firmware does.
         */
        qdev_prop_set_uint32(cpudev, "init-svtor", s->init_svtor);
        /*
         * Start all CPUs except CPU0 powered down. In real hardware it is
         * a configurable property of the SSE-200 which CPUs start powered up
         * (via the CPUWAIT0_RST and CPUWAIT1_RST parameters), but since all
         * the boards we care about start CPU0 and leave CPU1 powered off,
         * we hard-code that for now. We can add QOM properties for this
         * CPUs start powered down if the corresponding bit in the CPUWAIT
         * register is 1. In real hardware the CPUWAIT register reset value is
         * a configurable property of the SSE-200 (via the CPUWAIT0_RST and
         * CPUWAIT1_RST parameters), but since all the boards we care about
         * start CPU0 and leave CPU1 powered off, we hard-code that in
         * info->cpuwait_rst for now. We can add QOM properties for this
         * later if necessary.
         */
        if (i > 0) {
        if (extract32(info->cpuwait_rst, i, 1)) {
            object_property_set_bool(cpuobj, true, "start-powered-off", &err);
            if (err) {
                error_propagate(errp, err);
@@ -766,22 +773,28 @@ static void armsse_realize(DeviceState *dev, Error **errp)
    }

    if (info->has_mhus) {
        /*
         * An SSE-200 with only one CPU should have only one MHU created,
         * with the region where the second MHU usually is being RAZ/WI.
         * We don't implement that SSE-200 config; if we want to support
         * it then this code needs to be enhanced to handle creating the
         * RAZ/WI region instead of the second MHU.
         */
        assert(info->num_cpus == ARRAY_SIZE(s->mhu));

        for (i = 0; i < ARRAY_SIZE(s->mhu); i++) {
            char *name;
            char *port;
            int cpunum;
            SysBusDevice *mhu_sbd = SYS_BUS_DEVICE(&s->mhu[i]);

            name = g_strdup_printf("MHU%d", i);
            qdev_prop_set_string(DEVICE(&s->mhu[i]), "name", name);
            qdev_prop_set_uint64(DEVICE(&s->mhu[i]), "size", 0x1000);
            object_property_set_bool(OBJECT(&s->mhu[i]), true,
                                     "realized", &err);
            g_free(name);
            if (err) {
                error_propagate(errp, err);
                return;
            }
            port = g_strdup_printf("port[%d]", i + 3);
            mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mhu[i]), 0);
            mr = sysbus_mmio_get_region(mhu_sbd, 0);
            object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr),
                                     port, &err);
            g_free(port);
@@ -789,6 +802,20 @@ static void armsse_realize(DeviceState *dev, Error **errp)
                error_propagate(errp, err);
                return;
            }

            /*
             * Each MHU has an irq line for each CPU:
             *  MHU 0 irq line 0 -> CPU 0 IRQ 6
             *  MHU 0 irq line 1 -> CPU 1 IRQ 6
             *  MHU 1 irq line 0 -> CPU 0 IRQ 7
             *  MHU 1 irq line 1 -> CPU 1 IRQ 7
             */
            for (cpunum = 0; cpunum < info->num_cpus; cpunum++) {
                DeviceState *cpudev = DEVICE(&s->armv7m[cpunum]);

                sysbus_connect_irq(mhu_sbd, cpunum,
                                   qdev_get_gpio_in(cpudev, 6 + i));
            }
        }
    }

@@ -977,6 +1004,14 @@ static void armsse_realize(DeviceState *dev, Error **errp)
    /* System information registers */
    sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysinfo), 0, 0x40020000);
    /* System control registers */
    object_property_set_int(OBJECT(&s->sysctl), info->sys_version,
                            "SYS_VERSION", &err);
    object_property_set_int(OBJECT(&s->sysctl), info->cpuwait_rst,
                            "CPUWAIT_RST", &err);
    object_property_set_int(OBJECT(&s->sysctl), s->init_svtor,
                            "INITSVTOR0_RST", &err);
    object_property_set_int(OBJECT(&s->sysctl), s->init_svtor,
                            "INITSVTOR1_RST", &err);
    object_property_set_bool(OBJECT(&s->sysctl), true, "realized", &err);
    if (err) {
        error_propagate(errp, err);
+1 −0
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@ obj-$(CONFIG_IOTKIT_SECCTL) += iotkit-secctl.o
obj-$(CONFIG_IOTKIT_SYSCTL) += iotkit-sysctl.o
obj-$(CONFIG_IOTKIT_SYSINFO) += iotkit-sysinfo.o
obj-$(CONFIG_ARMSSE_CPUID) += armsse-cpuid.o
obj-$(CONFIG_ARMSSE_MHU) += armsse-mhu.o

obj-$(CONFIG_PVPANIC) += pvpanic.o
obj-$(CONFIG_AUX) += auxbus.o

hw/misc/armsse-mhu.c

0 → 100644
+198 −0
Original line number Diff line number Diff line
/*
 * ARM SSE-200 Message Handling Unit (MHU)
 *
 * Copyright (c) 2019 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 Message Handling Unit (MHU) which is part of the
 * Arm SSE-200 and documented in
 * http://infocenter.arm.com/help/topic/com.arm.doc.101104_0100_00_en/corelink_sse200_subsystem_for_embedded_technical_reference_manual_101104_0100_00_en.pdf
 */

#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/armsse-mhu.h"

REG32(CPU0INTR_STAT, 0x0)
REG32(CPU0INTR_SET, 0x4)
REG32(CPU0INTR_CLR, 0x8)
REG32(CPU1INTR_STAT, 0x10)
REG32(CPU1INTR_SET, 0x14)
REG32(CPU1INTR_CLR, 0x18)
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)

/* Valid bits in the interrupt registers. If any are set the IRQ is raised */
#define INTR_MASK 0xf

/* PID/CID values */
static const int armsse_mhu_id[] = {
    0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
    0x56, 0xb8, 0x0b, 0x00, /* PID0..PID3 */
    0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
};

static void armsse_mhu_update(ARMSSEMHU *s)
{
    qemu_set_irq(s->cpu0irq, s->cpu0intr != 0);
    qemu_set_irq(s->cpu1irq, s->cpu1intr != 0);
}

static uint64_t armsse_mhu_read(void *opaque, hwaddr offset, unsigned size)
{
    ARMSSEMHU *s = ARMSSE_MHU(opaque);
    uint64_t r;

    switch (offset) {
    case A_CPU0INTR_STAT:
        r = s->cpu0intr;
        break;

    case A_CPU1INTR_STAT:
        r = s->cpu1intr;
        break;

    case A_PID4 ... A_CID3:
        r = armsse_mhu_id[(offset - A_PID4) / 4];
        break;

    case A_CPU0INTR_SET:
    case A_CPU0INTR_CLR:
    case A_CPU1INTR_SET:
    case A_CPU1INTR_CLR:
        qemu_log_mask(LOG_GUEST_ERROR,
                      "SSE MHU: read of write-only register at offset 0x%x\n",
                      (int)offset);
        r = 0;
        break;

    default:
        qemu_log_mask(LOG_GUEST_ERROR,
                      "SSE MHU read: bad offset 0x%x\n", (int)offset);
        r = 0;
        break;
    }
    trace_armsse_mhu_read(offset, r, size);
    return r;
}

static void armsse_mhu_write(void *opaque, hwaddr offset,
                             uint64_t value, unsigned size)
{
    ARMSSEMHU *s = ARMSSE_MHU(opaque);

    trace_armsse_mhu_write(offset, value, size);

    switch (offset) {
    case A_CPU0INTR_SET:
        s->cpu0intr |= (value & INTR_MASK);
        break;
    case A_CPU0INTR_CLR:
        s->cpu0intr &= ~(value & INTR_MASK);
        break;
    case A_CPU1INTR_SET:
        s->cpu1intr |= (value & INTR_MASK);
        break;
    case A_CPU1INTR_CLR:
        s->cpu1intr &= ~(value & INTR_MASK);
        break;

    case A_CPU0INTR_STAT:
    case A_CPU1INTR_STAT:
    case A_PID4 ... A_CID3:
        qemu_log_mask(LOG_GUEST_ERROR,
                      "SSE MHU: write to read-only register at offset 0x%x\n",
                      (int)offset);
        break;

    default:
        qemu_log_mask(LOG_GUEST_ERROR,
                      "SSE MHU write: bad offset 0x%x\n", (int)offset);
        break;
    }

    armsse_mhu_update(s);
}

static const MemoryRegionOps armsse_mhu_ops = {
    .read = armsse_mhu_read,
    .write = armsse_mhu_write,
    .endianness = DEVICE_LITTLE_ENDIAN,
    .valid.min_access_size = 4,
    .valid.max_access_size = 4,
};

static void armsse_mhu_reset(DeviceState *dev)
{
    ARMSSEMHU *s = ARMSSE_MHU(dev);

    s->cpu0intr = 0;
    s->cpu1intr = 0;
}

static const VMStateDescription armsse_mhu_vmstate = {
    .name = "armsse-mhu",
    .version_id = 1,
    .minimum_version_id = 1,
    .fields = (VMStateField[]) {
        VMSTATE_UINT32(cpu0intr, ARMSSEMHU),
        VMSTATE_UINT32(cpu1intr, ARMSSEMHU),
        VMSTATE_END_OF_LIST()
    },
};

static void armsse_mhu_init(Object *obj)
{
    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    ARMSSEMHU *s = ARMSSE_MHU(obj);

    memory_region_init_io(&s->iomem, obj, &armsse_mhu_ops,
                          s, "armsse-mhu", 0x1000);
    sysbus_init_mmio(sbd, &s->iomem);
    sysbus_init_irq(sbd, &s->cpu0irq);
    sysbus_init_irq(sbd, &s->cpu1irq);
}

static void armsse_mhu_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(klass);

    dc->reset = armsse_mhu_reset;
    dc->vmsd = &armsse_mhu_vmstate;
}

static const TypeInfo armsse_mhu_info = {
    .name = TYPE_ARMSSE_MHU,
    .parent = TYPE_SYS_BUS_DEVICE,
    .instance_size = sizeof(ARMSSEMHU),
    .instance_init = armsse_mhu_init,
    .class_init = armsse_mhu_class_init,
};

static void armsse_mhu_register_types(void)
{
    type_register_static(&armsse_mhu_info);
}

type_init(armsse_mhu_register_types);
Loading