mirror of https://gitee.com/openkylin/qemu.git
target-arm queue:
* Implement priority handling properly via GICC_APR * Enable TZ extensions on the GIC if we're using them * Minor preparatory patches for EL3 support * cadence_gem: Correct Marvell PHY SPCFC reset value * Support AHCI in ZynqMP -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJV7xFhAAoJEDwlJe0UNgzeobsP/iNDaNaLy/KDS2sErdPlHN6W 1woHq4dP9Kv6DC55KE2lINDd/Y7XeFSz5A2hqVhOqLQMXysfW7gbT1KEWr7nw4Da c2fQgPPCsYd1XSB3PXHXJSYP0BgFNjRncvBgM4V/w4cPmETHPqaYBs2gQCm81Sg5 FnjIKUJlr1DTE4jyJu4wu7lbJIeIS2bZnFqORd6uadoslyu+5yB0NKsEjqB88U+4 +aRDFo3aSpUBqIy0KGIB73pxCwcHu6bqgmRXiORHt96OIzhMpgPLtwk/wjY3gvi8 bD04ImGV5aQZpK+feIqj9AjJzL+Lq8hUQXrHT0q9tcBpXMrRjTcHZrdAy4/fJHEL sbO13KyVHAINSJAzNHWF+702iEvhc95EEV1mdftZ1EkNkSRnVpSS5mmjxriCLHB/ t6b5d60Mqbou71LL1DCcbj2eMxRNwjhwfkGfqXxo7DVSORonV2DSRSDqIy+X24gV pEfphi3UGL7hDRJwx42nFtW3ezPB5tz0WgDT1eS32H5O2JSr0NRLS49mT6Jqbd4J 2JWeEzgcRYcRymJMlZANNhL+7CORT7ZzjXRitTheq91pkkcf9SBkl55OI0MXH/JG vgqwwLKJiKZLxi1BJUJxvN828udH4EpIB6wc5RV9LAsTVoEftYdpc5O3Us4ae03+ Dca5VcsBowY00cOIeYe5 =hLY2 -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20150908' into staging target-arm queue: * Implement priority handling properly via GICC_APR * Enable TZ extensions on the GIC if we're using them * Minor preparatory patches for EL3 support * cadence_gem: Correct Marvell PHY SPCFC reset value * Support AHCI in ZynqMP # gpg: Signature made Tue 08 Sep 2015 17:48:33 BST using RSA key ID 14360CDE # 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>" * remotes/pmaydell/tags/pull-target-arm-20150908: xlnx-zynqmp: Connect the sysbus AHCI to ZynqMP xlnx-zynqmp.c: Convert some of the error_propagate() calls to error_abort ahci.c: Don't assume AHCIState's parent is AHCIPCIState ahci: Separate the AHCI state structure into the header cadence_gem: Correct Marvell PHY SPCFC reset value target-arm: Add AArch64 access to PAR_EL1 target-arm: Correct opc1 for AT_S12Exx target-arm: Log the target EL when taking exceptions target-arm: Fix default_exception_el() function for the case when EL3 is not supported hw/arm/virt: Enable TZ extensions on the GIC if we are using them hw/arm/virt: Default to not providing TrustZone support hw/cpu/{a15mpcore, a9mpcore}: enable TrustZone in GIC if it is enabled in CPUs hw/intc/arm_gic_common: Configure IRQs as NS if doing direct NS kernel boot hw/arm: new interface for devices which need to behave differently for kernel boot qom: Add recursive version of object_child_for_each hw/intc/arm_gic: Actually set the active bits for active interrupts hw/intc/arm_gic: Drop running_irq and last_active arrays hw/intc/arm_gic: Fix handling of GICC_APR<n>, GICC_NSAPR<n> registers hw/intc/arm_gic: Running priority is group priority, not full priority armv7m_nvic: Implement ICSR without using internal GIC state Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
fc04a730b7
|
@ -10,6 +10,7 @@
|
|||
#include "config.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/arm/arm.h"
|
||||
#include "hw/arm/linux-boot-if.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/loader.h"
|
||||
|
@ -555,6 +556,20 @@ static void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key,
|
|||
fw_cfg_add_bytes(fw_cfg, data_key, data, size);
|
||||
}
|
||||
|
||||
static int do_arm_linux_init(Object *obj, void *opaque)
|
||||
{
|
||||
if (object_dynamic_cast(obj, TYPE_ARM_LINUX_BOOT_IF)) {
|
||||
ARMLinuxBootIf *albif = ARM_LINUX_BOOT_IF(obj);
|
||||
ARMLinuxBootIfClass *albifc = ARM_LINUX_BOOT_IF_GET_CLASS(obj);
|
||||
struct arm_boot_info *info = opaque;
|
||||
|
||||
if (albifc->arm_linux_init) {
|
||||
albifc->arm_linux_init(albif, info->secure_boot);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void arm_load_kernel_notify(Notifier *notifier, void *data)
|
||||
{
|
||||
CPUState *cs;
|
||||
|
@ -778,6 +793,12 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data)
|
|||
if (info->nb_cpus > 1) {
|
||||
info->write_secondary_boot(cpu, info);
|
||||
}
|
||||
|
||||
/* Notify devices which need to fake up firmware initialization
|
||||
* that we're doing a direct kernel boot.
|
||||
*/
|
||||
object_child_foreach_recursive(object_get_root(),
|
||||
do_arm_linux_init, info);
|
||||
}
|
||||
info->is_linux = is_linux;
|
||||
|
||||
|
@ -803,3 +824,16 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
|||
qemu_register_reset(do_cpu_reset, ARM_CPU(cs));
|
||||
}
|
||||
}
|
||||
|
||||
static const TypeInfo arm_linux_boot_if_info = {
|
||||
.name = TYPE_ARM_LINUX_BOOT_IF,
|
||||
.parent = TYPE_INTERFACE,
|
||||
.class_size = sizeof(ARMLinuxBootIfClass),
|
||||
};
|
||||
|
||||
static void arm_linux_boot_register_types(void)
|
||||
{
|
||||
type_register_static(&arm_linux_boot_if_info);
|
||||
}
|
||||
|
||||
type_init(arm_linux_boot_register_types)
|
||||
|
|
|
@ -396,7 +396,7 @@ static void create_v2m(VirtBoardInfo *vbi, qemu_irq *pic)
|
|||
fdt_add_v2m_gic_node(vbi);
|
||||
}
|
||||
|
||||
static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic)
|
||||
static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, bool secure)
|
||||
{
|
||||
/* We create a standalone GIC v2 */
|
||||
DeviceState *gicdev;
|
||||
|
@ -413,6 +413,9 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic)
|
|||
* interrupts; there are always 32 of the former (mandated by GIC spec).
|
||||
*/
|
||||
qdev_prop_set_uint32(gicdev, "num-irq", NUM_IRQS + 32);
|
||||
if (!kvm_irqchip_in_kernel()) {
|
||||
qdev_prop_set_bit(gicdev, "has-security-extensions", secure);
|
||||
}
|
||||
qdev_init_nofail(gicdev);
|
||||
gicbusdev = SYS_BUS_DEVICE(gicdev);
|
||||
sysbus_mmio_map(gicbusdev, 0, vbi->memmap[VIRT_GIC_DIST].base);
|
||||
|
@ -967,7 +970,7 @@ static void machvirt_init(MachineState *machine)
|
|||
|
||||
create_flash(vbi);
|
||||
|
||||
create_gic(vbi, pic);
|
||||
create_gic(vbi, pic, vms->secure);
|
||||
|
||||
create_uart(vbi, pic);
|
||||
|
||||
|
@ -1044,8 +1047,11 @@ static void virt_instance_init(Object *obj)
|
|||
{
|
||||
VirtMachineState *vms = VIRT_MACHINE(obj);
|
||||
|
||||
/* EL3 is enabled by default on virt */
|
||||
vms->secure = true;
|
||||
/* EL3 is disabled by default on virt: this makes us consistent
|
||||
* between KVM and TCG for this board, and it also allows us to
|
||||
* boot UEFI blobs which assume no TrustZone support.
|
||||
*/
|
||||
vms->secure = false;
|
||||
object_property_add_bool(obj, "secure", virt_get_secure,
|
||||
virt_set_secure, NULL);
|
||||
object_property_set_description(obj, "secure",
|
||||
|
|
|
@ -28,6 +28,10 @@
|
|||
#define GIC_DIST_ADDR 0xf9010000
|
||||
#define GIC_CPU_ADDR 0xf9020000
|
||||
|
||||
#define SATA_INTR 133
|
||||
#define SATA_ADDR 0xFD0C0000
|
||||
#define SATA_NUM_PORTS 2
|
||||
|
||||
static const uint64_t gem_addr[XLNX_ZYNQMP_NUM_GEMS] = {
|
||||
0xFF0B0000, 0xFF0C0000, 0xFF0D0000, 0xFF0E0000,
|
||||
};
|
||||
|
@ -90,6 +94,9 @@ static void xlnx_zynqmp_init(Object *obj)
|
|||
object_initialize(&s->uart[i], sizeof(s->uart[i]), TYPE_CADENCE_UART);
|
||||
qdev_set_parent_bus(DEVICE(&s->uart[i]), sysbus_get_default());
|
||||
}
|
||||
|
||||
object_initialize(&s->sata, sizeof(s->sata), TYPE_SYSBUS_AHCI);
|
||||
qdev_set_parent_bus(DEVICE(&s->sata), sysbus_get_default());
|
||||
}
|
||||
|
||||
static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
|
||||
|
@ -162,12 +169,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
|
|||
g_free(name);
|
||||
|
||||
object_property_set_int(OBJECT(&s->apu_cpu[i]), GIC_BASE_ADDR,
|
||||
"reset-cbar", &err);
|
||||
if (err) {
|
||||
error_propagate((errp), (err));
|
||||
return;
|
||||
}
|
||||
|
||||
"reset-cbar", &error_abort);
|
||||
object_property_set_bool(OBJECT(&s->apu_cpu[i]), true, "realized",
|
||||
&err);
|
||||
if (err) {
|
||||
|
@ -200,12 +202,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
|
|||
g_free(name);
|
||||
|
||||
object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, "reset-hivecs",
|
||||
&err);
|
||||
if (err != NULL) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
&error_abort);
|
||||
object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, "realized",
|
||||
&err);
|
||||
if (err) {
|
||||
|
@ -250,6 +247,17 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
|
|||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0,
|
||||
gic_spi[uart_intr[i]]);
|
||||
}
|
||||
|
||||
object_property_set_int(OBJECT(&s->sata), SATA_NUM_PORTS, "num-ports",
|
||||
&error_abort);
|
||||
object_property_set_bool(OBJECT(&s->sata), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->sata), 0, SATA_ADDR);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->sata), 0, gic_spi[SATA_INTR]);
|
||||
}
|
||||
|
||||
static Property xlnx_zynqmp_props[] = {
|
||||
|
|
|
@ -52,10 +52,23 @@ static void a15mp_priv_realize(DeviceState *dev, Error **errp)
|
|||
SysBusDevice *busdev;
|
||||
int i;
|
||||
Error *err = NULL;
|
||||
bool has_el3;
|
||||
Object *cpuobj;
|
||||
|
||||
gicdev = DEVICE(&s->gic);
|
||||
qdev_prop_set_uint32(gicdev, "num-cpu", s->num_cpu);
|
||||
qdev_prop_set_uint32(gicdev, "num-irq", s->num_irq);
|
||||
|
||||
if (!kvm_irqchip_in_kernel()) {
|
||||
/* Make the GIC's TZ support match the CPUs. We assume that
|
||||
* either all the CPUs have TZ, or none do.
|
||||
*/
|
||||
cpuobj = OBJECT(qemu_get_cpu(0));
|
||||
has_el3 = object_property_find(cpuobj, "has_el3", &error_abort) &&
|
||||
object_property_get_bool(cpuobj, "has_el3", &error_abort);
|
||||
qdev_prop_set_bit(gicdev, "has-security-extensions", has_el3);
|
||||
}
|
||||
|
||||
object_property_set_bool(OBJECT(&s->gic), true, "realized", &err);
|
||||
if (err != NULL) {
|
||||
error_propagate(errp, err);
|
||||
|
|
|
@ -49,6 +49,8 @@ static void a9mp_priv_realize(DeviceState *dev, Error **errp)
|
|||
*wdtbusdev;
|
||||
Error *err = NULL;
|
||||
int i;
|
||||
bool has_el3;
|
||||
Object *cpuobj;
|
||||
|
||||
scudev = DEVICE(&s->scu);
|
||||
qdev_prop_set_uint32(scudev, "num-cpu", s->num_cpu);
|
||||
|
@ -62,6 +64,15 @@ static void a9mp_priv_realize(DeviceState *dev, Error **errp)
|
|||
gicdev = DEVICE(&s->gic);
|
||||
qdev_prop_set_uint32(gicdev, "num-cpu", s->num_cpu);
|
||||
qdev_prop_set_uint32(gicdev, "num-irq", s->num_irq);
|
||||
|
||||
/* Make the GIC's TZ support match the CPUs. We assume that
|
||||
* either all the CPUs have TZ, or none do.
|
||||
*/
|
||||
cpuobj = OBJECT(qemu_get_cpu(0));
|
||||
has_el3 = object_property_find(cpuobj, "has_el3", &error_abort) &&
|
||||
object_property_get_bool(cpuobj, "has_el3", &error_abort);
|
||||
qdev_prop_set_bit(gicdev, "has-security-extensions", has_el3);
|
||||
|
||||
object_property_set_bool(OBJECT(&s->gic), true, "realized", &err);
|
||||
if (err != NULL) {
|
||||
error_propagate(errp, err);
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include <hw/pci/msi.h>
|
||||
#include <hw/i386/pc.h>
|
||||
#include <hw/pci/pci.h>
|
||||
#include <hw/sysbus.h>
|
||||
|
||||
#include "qemu/error-report.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
|
@ -122,9 +121,9 @@ static uint32_t ahci_port_read(AHCIState *s, int port, int offset)
|
|||
|
||||
static void ahci_irq_raise(AHCIState *s, AHCIDevice *dev)
|
||||
{
|
||||
AHCIPCIState *d = container_of(s, AHCIPCIState, ahci);
|
||||
PCIDevice *pci_dev =
|
||||
(PCIDevice *)object_dynamic_cast(OBJECT(d), TYPE_PCI_DEVICE);
|
||||
DeviceState *dev_state = s->container;
|
||||
PCIDevice *pci_dev = (PCIDevice *) object_dynamic_cast(OBJECT(dev_state),
|
||||
TYPE_PCI_DEVICE);
|
||||
|
||||
DPRINTF(0, "raise irq\n");
|
||||
|
||||
|
@ -137,9 +136,9 @@ static void ahci_irq_raise(AHCIState *s, AHCIDevice *dev)
|
|||
|
||||
static void ahci_irq_lower(AHCIState *s, AHCIDevice *dev)
|
||||
{
|
||||
AHCIPCIState *d = container_of(s, AHCIPCIState, ahci);
|
||||
PCIDevice *pci_dev =
|
||||
(PCIDevice *)object_dynamic_cast(OBJECT(d), TYPE_PCI_DEVICE);
|
||||
DeviceState *dev_state = s->container;
|
||||
PCIDevice *pci_dev = (PCIDevice *) object_dynamic_cast(OBJECT(dev_state),
|
||||
TYPE_PCI_DEVICE);
|
||||
|
||||
DPRINTF(0, "lower irq\n");
|
||||
|
||||
|
@ -1437,6 +1436,7 @@ void ahci_init(AHCIState *s, DeviceState *qdev, AddressSpace *as, int ports)
|
|||
s->as = as;
|
||||
s->ports = ports;
|
||||
s->dev = g_new0(AHCIDevice, ports);
|
||||
s->container = qdev;
|
||||
ahci_reg_init(s);
|
||||
/* XXX BAR size should be 1k, but that breaks, so bump it to 4k for now */
|
||||
memory_region_init_io(&s->mem, OBJECT(qdev), &ahci_mem_ops, s,
|
||||
|
@ -1625,18 +1625,6 @@ const VMStateDescription vmstate_ahci = {
|
|||
},
|
||||
};
|
||||
|
||||
#define TYPE_SYSBUS_AHCI "sysbus-ahci"
|
||||
#define SYSBUS_AHCI(obj) OBJECT_CHECK(SysbusAHCIState, (obj), TYPE_SYSBUS_AHCI)
|
||||
|
||||
typedef struct SysbusAHCIState {
|
||||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
/*< public >*/
|
||||
|
||||
AHCIState ahci;
|
||||
uint32_t num_ports;
|
||||
} SysbusAHCIState;
|
||||
|
||||
static const VMStateDescription vmstate_sysbus_ahci = {
|
||||
.name = "sysbus-ahci",
|
||||
.fields = (VMStateField[]) {
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#ifndef HW_IDE_AHCI_H
|
||||
#define HW_IDE_AHCI_H
|
||||
|
||||
#include <hw/sysbus.h>
|
||||
|
||||
#define AHCI_MEM_BAR_SIZE 0x1000
|
||||
#define AHCI_MAX_PORTS 32
|
||||
#define AHCI_MAX_SG 168 /* hardware max is 64K */
|
||||
|
@ -285,6 +287,8 @@ struct AHCIDevice {
|
|||
};
|
||||
|
||||
typedef struct AHCIState {
|
||||
DeviceState *container;
|
||||
|
||||
AHCIDevice *dev;
|
||||
AHCIControlRegs control_regs;
|
||||
MemoryRegion mem;
|
||||
|
@ -369,4 +373,16 @@ void ahci_reset(AHCIState *s);
|
|||
|
||||
void ahci_ide_create_devs(PCIDevice *dev, DriveInfo **hd);
|
||||
|
||||
#define TYPE_SYSBUS_AHCI "sysbus-ahci"
|
||||
#define SYSBUS_AHCI(obj) OBJECT_CHECK(SysbusAHCIState, (obj), TYPE_SYSBUS_AHCI)
|
||||
|
||||
typedef struct SysbusAHCIState {
|
||||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
/*< public >*/
|
||||
|
||||
AHCIState ahci;
|
||||
uint32_t num_ports;
|
||||
} SysbusAHCIState;
|
||||
|
||||
#endif /* HW_IDE_AHCI_H */
|
||||
|
|
|
@ -219,15 +219,99 @@ static uint16_t gic_get_current_pending_irq(GICState *s, int cpu,
|
|||
return pending_irq;
|
||||
}
|
||||
|
||||
static void gic_set_running_irq(GICState *s, int cpu, int irq)
|
||||
static int gic_get_group_priority(GICState *s, int cpu, int irq)
|
||||
{
|
||||
s->running_irq[cpu] = irq;
|
||||
if (irq == 1023) {
|
||||
s->running_priority[cpu] = 0x100;
|
||||
/* Return the group priority of the specified interrupt
|
||||
* (which is the top bits of its priority, with the number
|
||||
* of bits masked determined by the applicable binary point register).
|
||||
*/
|
||||
int bpr;
|
||||
uint32_t mask;
|
||||
|
||||
if (gic_has_groups(s) &&
|
||||
!(s->cpu_ctlr[cpu] & GICC_CTLR_CBPR) &&
|
||||
GIC_TEST_GROUP(irq, (1 << cpu))) {
|
||||
bpr = s->abpr[cpu];
|
||||
} else {
|
||||
s->running_priority[cpu] = GIC_GET_PRIORITY(irq, cpu);
|
||||
bpr = s->bpr[cpu];
|
||||
}
|
||||
gic_update(s);
|
||||
|
||||
/* a BPR of 0 means the group priority bits are [7:1];
|
||||
* a BPR of 1 means they are [7:2], and so on down to
|
||||
* a BPR of 7 meaning no group priority bits at all.
|
||||
*/
|
||||
mask = ~0U << ((bpr & 7) + 1);
|
||||
|
||||
return GIC_GET_PRIORITY(irq, cpu) & mask;
|
||||
}
|
||||
|
||||
static void gic_activate_irq(GICState *s, int cpu, int irq)
|
||||
{
|
||||
/* Set the appropriate Active Priority Register bit for this IRQ,
|
||||
* and update the running priority.
|
||||
*/
|
||||
int prio = gic_get_group_priority(s, cpu, irq);
|
||||
int preemption_level = prio >> (GIC_MIN_BPR + 1);
|
||||
int regno = preemption_level / 32;
|
||||
int bitno = preemption_level % 32;
|
||||
|
||||
if (gic_has_groups(s) && GIC_TEST_GROUP(irq, (1 << cpu))) {
|
||||
s->nsapr[regno][cpu] &= (1 << bitno);
|
||||
} else {
|
||||
s->apr[regno][cpu] &= (1 << bitno);
|
||||
}
|
||||
|
||||
s->running_priority[cpu] = prio;
|
||||
GIC_SET_ACTIVE(irq, 1 << cpu);
|
||||
}
|
||||
|
||||
static int gic_get_prio_from_apr_bits(GICState *s, int cpu)
|
||||
{
|
||||
/* Recalculate the current running priority for this CPU based
|
||||
* on the set bits in the Active Priority Registers.
|
||||
*/
|
||||
int i;
|
||||
for (i = 0; i < GIC_NR_APRS; i++) {
|
||||
uint32_t apr = s->apr[i][cpu] | s->nsapr[i][cpu];
|
||||
if (!apr) {
|
||||
continue;
|
||||
}
|
||||
return (i * 32 + ctz32(apr)) << (GIC_MIN_BPR + 1);
|
||||
}
|
||||
return 0x100;
|
||||
}
|
||||
|
||||
static void gic_drop_prio(GICState *s, int cpu, int group)
|
||||
{
|
||||
/* Drop the priority of the currently active interrupt in the
|
||||
* specified group.
|
||||
*
|
||||
* Note that we can guarantee (because of the requirement to nest
|
||||
* GICC_IAR reads [which activate an interrupt and raise priority]
|
||||
* with GICC_EOIR writes [which drop the priority for the interrupt])
|
||||
* that the interrupt we're being called for is the highest priority
|
||||
* active interrupt, meaning that it has the lowest set bit in the
|
||||
* APR registers.
|
||||
*
|
||||
* If the guest does not honour the ordering constraints then the
|
||||
* behaviour of the GIC is UNPREDICTABLE, which for us means that
|
||||
* the values of the APR registers might become incorrect and the
|
||||
* running priority will be wrong, so interrupts that should preempt
|
||||
* might not do so, and interrupts that should not preempt might do so.
|
||||
*/
|
||||
int i;
|
||||
|
||||
for (i = 0; i < GIC_NR_APRS; i++) {
|
||||
uint32_t *papr = group ? &s->nsapr[i][cpu] : &s->apr[i][cpu];
|
||||
if (!*papr) {
|
||||
continue;
|
||||
}
|
||||
/* Clear lowest set bit */
|
||||
*papr &= *papr - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
s->running_priority[cpu] = gic_get_prio_from_apr_bits(s, cpu);
|
||||
}
|
||||
|
||||
uint32_t gic_acknowledge_irq(GICState *s, int cpu, MemTxAttrs attrs)
|
||||
|
@ -250,7 +334,6 @@ uint32_t gic_acknowledge_irq(GICState *s, int cpu, MemTxAttrs attrs)
|
|||
DPRINTF("ACK, pending interrupt (%d) has insufficient priority\n", irq);
|
||||
return 1023;
|
||||
}
|
||||
s->last_active[irq][cpu] = s->running_irq[cpu];
|
||||
|
||||
if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
|
||||
/* Clear pending flags for both level and edge triggered interrupts.
|
||||
|
@ -281,7 +364,8 @@ uint32_t gic_acknowledge_irq(GICState *s, int cpu, MemTxAttrs attrs)
|
|||
}
|
||||
}
|
||||
|
||||
gic_set_running_irq(s, cpu, irq);
|
||||
gic_activate_irq(s, cpu, irq);
|
||||
gic_update(s);
|
||||
DPRINTF("ACK %d\n", irq);
|
||||
return ret;
|
||||
}
|
||||
|
@ -411,8 +495,9 @@ static uint8_t gic_get_running_priority(GICState *s, int cpu, MemTxAttrs attrs)
|
|||
|
||||
void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs)
|
||||
{
|
||||
int update = 0;
|
||||
int cm = 1 << cpu;
|
||||
int group;
|
||||
|
||||
DPRINTF("EOI %d\n", irq);
|
||||
if (irq >= s->num_irq) {
|
||||
/* This handles two cases:
|
||||
|
@ -425,8 +510,9 @@ void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs)
|
|||
*/
|
||||
return;
|
||||
}
|
||||
if (s->running_irq[cpu] == 1023)
|
||||
if (s->running_priority[cpu] == 0x100) {
|
||||
return; /* No active IRQ. */
|
||||
}
|
||||
|
||||
if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) {
|
||||
/* Mark level triggered interrupts as pending if they are still
|
||||
|
@ -435,11 +521,12 @@ void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs)
|
|||
&& GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) {
|
||||
DPRINTF("Set %d pending mask %x\n", irq, cm);
|
||||
GIC_SET_PENDING(irq, cm);
|
||||
update = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (s->security_extn && !attrs.secure && !GIC_TEST_GROUP(irq, cm)) {
|
||||
group = gic_has_groups(s) && GIC_TEST_GROUP(irq, cm);
|
||||
|
||||
if (s->security_extn && !attrs.secure && !group) {
|
||||
DPRINTF("Non-secure EOI for Group0 interrupt %d ignored\n", irq);
|
||||
return;
|
||||
}
|
||||
|
@ -449,23 +536,9 @@ void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs)
|
|||
* i.e. go ahead and complete the irq anyway.
|
||||
*/
|
||||
|
||||
if (irq != s->running_irq[cpu]) {
|
||||
/* Complete an IRQ that is not currently running. */
|
||||
int tmp = s->running_irq[cpu];
|
||||
while (s->last_active[tmp][cpu] != 1023) {
|
||||
if (s->last_active[tmp][cpu] == irq) {
|
||||
s->last_active[tmp][cpu] = s->last_active[irq][cpu];
|
||||
break;
|
||||
}
|
||||
tmp = s->last_active[tmp][cpu];
|
||||
}
|
||||
if (update) {
|
||||
gic_update(s);
|
||||
}
|
||||
} else {
|
||||
/* Complete the current running IRQ. */
|
||||
gic_set_running_irq(s, cpu, s->last_active[s->running_irq[cpu]][cpu]);
|
||||
}
|
||||
gic_drop_prio(s, cpu, group);
|
||||
GIC_CLEAR_ACTIVE(irq, cm);
|
||||
gic_update(s);
|
||||
}
|
||||
|
||||
static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs)
|
||||
|
@ -922,6 +995,68 @@ static MemTxResult gic_dist_write(void *opaque, hwaddr offset, uint64_t data,
|
|||
}
|
||||
}
|
||||
|
||||
static inline uint32_t gic_apr_ns_view(GICState *s, int cpu, int regno)
|
||||
{
|
||||
/* Return the Nonsecure view of GICC_APR<regno>. This is the
|
||||
* second half of GICC_NSAPR.
|
||||
*/
|
||||
switch (GIC_MIN_BPR) {
|
||||
case 0:
|
||||
if (regno < 2) {
|
||||
return s->nsapr[regno + 2][cpu];
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (regno == 0) {
|
||||
return s->nsapr[regno + 1][cpu];
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (regno == 0) {
|
||||
return extract32(s->nsapr[0][cpu], 16, 16);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (regno == 0) {
|
||||
return extract32(s->nsapr[0][cpu], 8, 8);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void gic_apr_write_ns_view(GICState *s, int cpu, int regno,
|
||||
uint32_t value)
|
||||
{
|
||||
/* Write the Nonsecure view of GICC_APR<regno>. */
|
||||
switch (GIC_MIN_BPR) {
|
||||
case 0:
|
||||
if (regno < 2) {
|
||||
s->nsapr[regno + 2][cpu] = value;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (regno == 0) {
|
||||
s->nsapr[regno + 1][cpu] = value;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (regno == 0) {
|
||||
s->nsapr[0][cpu] = deposit32(s->nsapr[0][cpu], 16, 16, value);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (regno == 0) {
|
||||
s->nsapr[0][cpu] = deposit32(s->nsapr[0][cpu], 8, 8, value);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset,
|
||||
uint64_t *data, MemTxAttrs attrs)
|
||||
{
|
||||
|
@ -962,8 +1097,31 @@ static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset,
|
|||
}
|
||||
break;
|
||||
case 0xd0: case 0xd4: case 0xd8: case 0xdc:
|
||||
*data = s->apr[(offset - 0xd0) / 4][cpu];
|
||||
{
|
||||
int regno = (offset - 0xd0) / 4;
|
||||
|
||||
if (regno >= GIC_NR_APRS || s->revision != 2) {
|
||||
*data = 0;
|
||||
} else if (s->security_extn && !attrs.secure) {
|
||||
/* NS view of GICC_APR<n> is the top half of GIC_NSAPR<n> */
|
||||
*data = gic_apr_ns_view(s, regno, cpu);
|
||||
} else {
|
||||
*data = s->apr[regno][cpu];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0xe0: case 0xe4: case 0xe8: case 0xec:
|
||||
{
|
||||
int regno = (offset - 0xe0) / 4;
|
||||
|
||||
if (regno >= GIC_NR_APRS || s->revision != 2 || !gic_has_groups(s) ||
|
||||
(s->security_extn && !attrs.secure)) {
|
||||
*data = 0;
|
||||
} else {
|
||||
*data = s->nsapr[regno][cpu];
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"gic_cpu_read: Bad offset %x\n", (int)offset);
|
||||
|
@ -1001,8 +1159,33 @@ static MemTxResult gic_cpu_write(GICState *s, int cpu, int offset,
|
|||
}
|
||||
break;
|
||||
case 0xd0: case 0xd4: case 0xd8: case 0xdc:
|
||||
qemu_log_mask(LOG_UNIMP, "Writing APR not implemented\n");
|
||||
{
|
||||
int regno = (offset - 0xd0) / 4;
|
||||
|
||||
if (regno >= GIC_NR_APRS || s->revision != 2) {
|
||||
return MEMTX_OK;
|
||||
}
|
||||
if (s->security_extn && !attrs.secure) {
|
||||
/* NS view of GICC_APR<n> is the top half of GIC_NSAPR<n> */
|
||||
gic_apr_write_ns_view(s, regno, cpu, value);
|
||||
} else {
|
||||
s->apr[regno][cpu] = value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0xe0: case 0xe4: case 0xe8: case 0xec:
|
||||
{
|
||||
int regno = (offset - 0xe0) / 4;
|
||||
|
||||
if (regno >= GIC_NR_APRS || s->revision != 2) {
|
||||
return MEMTX_OK;
|
||||
}
|
||||
if (!gic_has_groups(s) || (s->security_extn && !attrs.secure)) {
|
||||
return MEMTX_OK;
|
||||
}
|
||||
s->nsapr[regno][cpu] = value;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"gic_cpu_write: Bad offset %x\n", (int)offset);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
*/
|
||||
|
||||
#include "gic_internal.h"
|
||||
#include "hw/arm/linux-boot-if.h"
|
||||
|
||||
static void gic_pre_save(void *opaque)
|
||||
{
|
||||
|
@ -59,8 +60,8 @@ static const VMStateDescription vmstate_gic_irq_state = {
|
|||
|
||||
static const VMStateDescription vmstate_gic = {
|
||||
.name = "arm_gic",
|
||||
.version_id = 10,
|
||||
.minimum_version_id = 10,
|
||||
.version_id = 12,
|
||||
.minimum_version_id = 12,
|
||||
.pre_save = gic_pre_save,
|
||||
.post_load = gic_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
|
@ -71,15 +72,14 @@ static const VMStateDescription vmstate_gic = {
|
|||
VMSTATE_UINT8_ARRAY(irq_target, GICState, GIC_MAXIRQ),
|
||||
VMSTATE_UINT8_2DARRAY(priority1, GICState, GIC_INTERNAL, GIC_NCPU),
|
||||
VMSTATE_UINT8_ARRAY(priority2, GICState, GIC_MAXIRQ - GIC_INTERNAL),
|
||||
VMSTATE_UINT16_2DARRAY(last_active, GICState, GIC_MAXIRQ, GIC_NCPU),
|
||||
VMSTATE_UINT8_2DARRAY(sgi_pending, GICState, GIC_NR_SGIS, GIC_NCPU),
|
||||
VMSTATE_UINT16_ARRAY(priority_mask, GICState, GIC_NCPU),
|
||||
VMSTATE_UINT16_ARRAY(running_irq, GICState, GIC_NCPU),
|
||||
VMSTATE_UINT16_ARRAY(running_priority, GICState, GIC_NCPU),
|
||||
VMSTATE_UINT16_ARRAY(current_pending, GICState, GIC_NCPU),
|
||||
VMSTATE_UINT8_ARRAY(bpr, GICState, GIC_NCPU),
|
||||
VMSTATE_UINT8_ARRAY(abpr, GICState, GIC_NCPU),
|
||||
VMSTATE_UINT32_2DARRAY(apr, GICState, GIC_NR_APRS, GIC_NCPU),
|
||||
VMSTATE_UINT32_2DARRAY(nsapr, GICState, GIC_NR_APRS, GIC_NCPU),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
@ -165,21 +165,35 @@ static void arm_gic_common_reset(DeviceState *dev)
|
|||
{
|
||||
GICState *s = ARM_GIC_COMMON(dev);
|
||||
int i, j;
|
||||
int resetprio;
|
||||
|
||||
/* If we're resetting a TZ-aware GIC as if secure firmware
|
||||
* had set it up ready to start a kernel in non-secure,
|
||||
* we need to set interrupt priorities to a "zero for the
|
||||
* NS view" value. This is particularly critical for the
|
||||
* priority_mask[] values, because if they are zero then NS
|
||||
* code cannot ever rewrite the priority to anything else.
|
||||
*/
|
||||
if (s->security_extn && s->irq_reset_nonsecure) {
|
||||
resetprio = 0x80;
|
||||
} else {
|
||||
resetprio = 0;
|
||||
}
|
||||
|
||||
memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state));
|
||||
for (i = 0 ; i < s->num_cpu; i++) {
|
||||
if (s->revision == REV_11MPCORE) {
|
||||
s->priority_mask[i] = 0xf0;
|
||||
} else {
|
||||
s->priority_mask[i] = 0;
|
||||
s->priority_mask[i] = resetprio;
|
||||
}
|
||||
s->current_pending[i] = 1023;
|
||||
s->running_irq[i] = 1023;
|
||||
s->running_priority[i] = 0x100;
|
||||
s->cpu_ctlr[i] = 0;
|
||||
s->bpr[i] = GIC_MIN_BPR;
|
||||
s->abpr[i] = GIC_MIN_ABPR;
|
||||
for (j = 0; j < GIC_INTERNAL; j++) {
|
||||
s->priority1[j][i] = 0;
|
||||
s->priority1[j][i] = resetprio;
|
||||
}
|
||||
for (j = 0; j < GIC_NR_SGIS; j++) {
|
||||
s->sgi_pending[j][i] = 0;
|
||||
|
@ -191,7 +205,7 @@ static void arm_gic_common_reset(DeviceState *dev)
|
|||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(s->priority2); i++) {
|
||||
s->priority2[i] = 0;
|
||||
s->priority2[i] = resetprio;
|
||||
}
|
||||
|
||||
for (i = 0; i < GIC_MAXIRQ; i++) {
|
||||
|
@ -202,9 +216,32 @@ static void arm_gic_common_reset(DeviceState *dev)
|
|||
s->irq_target[i] = 0;
|
||||
}
|
||||
}
|
||||
if (s->security_extn && s->irq_reset_nonsecure) {
|
||||
for (i = 0; i < GIC_MAXIRQ; i++) {
|
||||
GIC_SET_GROUP(i, ALL_CPU_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
s->ctlr = 0;
|
||||
}
|
||||
|
||||
static void arm_gic_common_linux_init(ARMLinuxBootIf *obj,
|
||||
bool secure_boot)
|
||||
{
|
||||
GICState *s = ARM_GIC_COMMON(obj);
|
||||
|
||||
if (s->security_extn && !secure_boot) {
|
||||
/* We're directly booting a kernel into NonSecure. If this GIC
|
||||
* implements the security extensions then we must configure it
|
||||
* to have all the interrupts be NonSecure (this is a job that
|
||||
* is done by the Secure boot firmware in real hardware, and in
|
||||
* this mode QEMU is acting as a minimalist firmware-and-bootloader
|
||||
* equivalent).
|
||||
*/
|
||||
s->irq_reset_nonsecure = true;
|
||||
}
|
||||
}
|
||||
|
||||
static Property arm_gic_common_properties[] = {
|
||||
DEFINE_PROP_UINT32("num-cpu", GICState, num_cpu, 1),
|
||||
DEFINE_PROP_UINT32("num-irq", GICState, num_irq, 32),
|
||||
|
@ -221,11 +258,13 @@ static Property arm_gic_common_properties[] = {
|
|||
static void arm_gic_common_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
ARMLinuxBootIfClass *albifc = ARM_LINUX_BOOT_IF_CLASS(klass);
|
||||
|
||||
dc->reset = arm_gic_common_reset;
|
||||
dc->realize = arm_gic_common_realize;
|
||||
dc->props = arm_gic_common_properties;
|
||||
dc->vmsd = &vmstate_gic;
|
||||
albifc->arm_linux_init = arm_gic_common_linux_init;
|
||||
}
|
||||
|
||||
static const TypeInfo arm_gic_common_type = {
|
||||
|
@ -235,6 +274,10 @@ static const TypeInfo arm_gic_common_type = {
|
|||
.class_size = sizeof(ARMGICCommonClass),
|
||||
.class_init = arm_gic_common_class_init,
|
||||
.abstract = true,
|
||||
.interfaces = (InterfaceInfo []) {
|
||||
{ TYPE_ARM_LINUX_BOOT_IF },
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
static void register_types(void)
|
||||
|
|
|
@ -185,26 +185,25 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
|
|||
return cpu->midr;
|
||||
case 0xd04: /* Interrupt Control State. */
|
||||
/* VECTACTIVE */
|
||||
val = s->gic.running_irq[0];
|
||||
cpu = ARM_CPU(current_cpu);
|
||||
val = cpu->env.v7m.exception;
|
||||
if (val == 1023) {
|
||||
val = 0;
|
||||
} else if (val >= 32) {
|
||||
val -= 16;
|
||||
}
|
||||
/* RETTOBASE */
|
||||
if (s->gic.running_irq[0] == 1023
|
||||
|| s->gic.last_active[s->gic.running_irq[0]][0] == 1023) {
|
||||
val |= (1 << 11);
|
||||
}
|
||||
/* VECTPENDING */
|
||||
if (s->gic.current_pending[0] != 1023)
|
||||
val |= (s->gic.current_pending[0] << 12);
|
||||
/* ISRPENDING */
|
||||
/* ISRPENDING and RETTOBASE */
|
||||
for (irq = 32; irq < s->num_irq; irq++) {
|
||||
if (s->gic.irq_state[irq].pending) {
|
||||
val |= (1 << 22);
|
||||
break;
|
||||
}
|
||||
if (irq != cpu->env.v7m.exception && s->gic.irq_state[irq].active) {
|
||||
val |= (1 << 11);
|
||||
}
|
||||
}
|
||||
/* PENDSTSET */
|
||||
if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending)
|
||||
|
|
|
@ -951,7 +951,7 @@ static void gem_phy_reset(CadenceGEMState *s)
|
|||
s->phy_regs[PHY_REG_1000BTSTAT] = 0x7C00;
|
||||
s->phy_regs[PHY_REG_EXTSTAT] = 0x3000;
|
||||
s->phy_regs[PHY_REG_PHYSPCFC_CTL] = 0x0078;
|
||||
s->phy_regs[PHY_REG_PHYSPCFC_ST] = 0xBC00;
|
||||
s->phy_regs[PHY_REG_PHYSPCFC_ST] = 0x7C00;
|
||||
s->phy_regs[PHY_REG_EXT_PHYSPCFC_CTL] = 0x0C60;
|
||||
s->phy_regs[PHY_REG_LED] = 0x4100;
|
||||
s->phy_regs[PHY_REG_EXT_PHYSPCFC_CTL2] = 0x000A;
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* hw/arm/linux-boot-if.h : interface for devices which need to behave
|
||||
* specially for direct boot of an ARM Linux kernel
|
||||
*/
|
||||
|
||||
#ifndef HW_ARM_LINUX_BOOT_IF_H
|
||||
#define HW_ARM_LINUX_BOOT_IF_H
|
||||
|
||||
#include "qom/object.h"
|
||||
|
||||
#define TYPE_ARM_LINUX_BOOT_IF "arm-linux-boot-if"
|
||||
#define ARM_LINUX_BOOT_IF_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(ARMLinuxBootIfClass, (klass), TYPE_ARM_LINUX_BOOT_IF)
|
||||
#define ARM_LINUX_BOOT_IF_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(ARMLinuxBootIfClass, (obj), TYPE_ARM_LINUX_BOOT_IF)
|
||||
#define ARM_LINUX_BOOT_IF(obj) \
|
||||
INTERFACE_CHECK(ARMLinuxBootIf, (obj), TYPE_ARM_LINUX_BOOT_IF)
|
||||
|
||||
typedef struct ARMLinuxBootIf {
|
||||
/*< private >*/
|
||||
Object parent_obj;
|
||||
} ARMLinuxBootIf;
|
||||
|
||||
typedef struct ARMLinuxBootIfClass {
|
||||
/*< private >*/
|
||||
InterfaceClass parent_class;
|
||||
|
||||
/*< public >*/
|
||||
/** arm_linux_init: configure the device for a direct boot
|
||||
* of an ARM Linux kernel (so that device reset puts it into
|
||||
* the state the kernel expects after firmware initialization,
|
||||
* rather than the true hardware reset state). This callback is
|
||||
* called once after machine construction is complete (before the
|
||||
* first system reset).
|
||||
*
|
||||
* @obj: the object implementing this interface
|
||||
* @secure_boot: true if we are booting Secure, false for NonSecure
|
||||
* (or for a CPU which doesn't support TrustZone)
|
||||
*/
|
||||
void (*arm_linux_init)(ARMLinuxBootIf *obj, bool secure_boot);
|
||||
} ARMLinuxBootIfClass;
|
||||
|
||||
#endif
|
|
@ -22,6 +22,8 @@
|
|||
#include "hw/intc/arm_gic.h"
|
||||
#include "hw/net/cadence_gem.h"
|
||||
#include "hw/char/cadence_uart.h"
|
||||
#include "hw/ide/pci.h"
|
||||
#include "hw/ide/ahci.h"
|
||||
|
||||
#define TYPE_XLNX_ZYNQMP "xlnx,zynqmp"
|
||||
#define XLNX_ZYNQMP(obj) OBJECT_CHECK(XlnxZynqMPState, (obj), \
|
||||
|
@ -60,6 +62,7 @@ typedef struct XlnxZynqMPState {
|
|||
|
||||
CadenceGEMState gem[XLNX_ZYNQMP_NUM_GEMS];
|
||||
CadenceUARTState uart[XLNX_ZYNQMP_NUM_UARTS];
|
||||
SysbusAHCIState sata;
|
||||
|
||||
char *boot_cpu;
|
||||
ARMCPU *boot_cpu_ptr;
|
||||
|
|
|
@ -68,7 +68,6 @@ typedef struct GICState {
|
|||
uint8_t irq_target[GIC_MAXIRQ];
|
||||
uint8_t priority1[GIC_INTERNAL][GIC_NCPU];
|
||||
uint8_t priority2[GIC_MAXIRQ - GIC_INTERNAL];
|
||||
uint16_t last_active[GIC_MAXIRQ][GIC_NCPU];
|
||||
/* For each SGI on the target CPU, we store 8 bits
|
||||
* indicating which source CPUs have made this SGI
|
||||
* pending on the target CPU. These correspond to
|
||||
|
@ -78,7 +77,6 @@ typedef struct GICState {
|
|||
uint8_t sgi_pending[GIC_NR_SGIS][GIC_NCPU];
|
||||
|
||||
uint16_t priority_mask[GIC_NCPU];
|
||||
uint16_t running_irq[GIC_NCPU];
|
||||
uint16_t running_priority[GIC_NCPU];
|
||||
uint16_t current_pending[GIC_NCPU];
|
||||
|
||||
|
@ -96,16 +94,9 @@ typedef struct GICState {
|
|||
* If an interrupt for preemption level X is active, then
|
||||
* APRn[X mod 32] == 0b1, where n = X / 32
|
||||
* otherwise the bit is clear.
|
||||
*
|
||||
* TODO: rewrite the interrupt acknowlege/complete routines to use
|
||||
* the APR registers to track the necessary information to update
|
||||
* s->running_priority[] on interrupt completion (ie completely remove
|
||||
* last_active[][] and running_irq[]). This will be necessary if we ever
|
||||
* want to support TCG<->KVM migration, or TCG guests which can
|
||||
* do power management involving powering down and restarting
|
||||
* the GIC.
|
||||
*/
|
||||
uint32_t apr[GIC_NR_APRS][GIC_NCPU];
|
||||
uint32_t nsapr[GIC_NR_APRS][GIC_NCPU];
|
||||
|
||||
uint32_t num_cpu;
|
||||
|
||||
|
@ -118,6 +109,7 @@ typedef struct GICState {
|
|||
uint32_t num_irq;
|
||||
uint32_t revision;
|
||||
bool security_extn;
|
||||
bool irq_reset_nonsecure; /* configure IRQs as group 1 (NS) on reset? */
|
||||
int dev_fd; /* kvm device fd if backed by kvm vgic support */
|
||||
} GICState;
|
||||
|
||||
|
|
|
@ -1493,6 +1493,21 @@ void object_property_set_description(Object *obj, const char *name,
|
|||
int object_child_foreach(Object *obj, int (*fn)(Object *child, void *opaque),
|
||||
void *opaque);
|
||||
|
||||
/**
|
||||
* object_child_foreach_recursive:
|
||||
* @obj: the object whose children will be navigated
|
||||
* @fn: the iterator function to be called
|
||||
* @opaque: an opaque value that will be passed to the iterator
|
||||
*
|
||||
* Call @fn passing each child of @obj and @opaque to it, until @fn returns
|
||||
* non-zero. Calls recursively, all child nodes of @obj will also be passed
|
||||
* all the way down to the leaf nodes of the tree. Depth first ordering.
|
||||
*
|
||||
* Returns: The last value returned by @fn, or 0 if there is no child.
|
||||
*/
|
||||
int object_child_foreach_recursive(Object *obj,
|
||||
int (*fn)(Object *child, void *opaque),
|
||||
void *opaque);
|
||||
/**
|
||||
* container_get:
|
||||
* @root: root of the #path, e.g., object_get_root()
|
||||
|
|
25
qom/object.c
25
qom/object.c
|
@ -775,23 +775,42 @@ void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),
|
|||
enumerating_types = false;
|
||||
}
|
||||
|
||||
int object_child_foreach(Object *obj, int (*fn)(Object *child, void *opaque),
|
||||
void *opaque)
|
||||
static int do_object_child_foreach(Object *obj,
|
||||
int (*fn)(Object *child, void *opaque),
|
||||
void *opaque, bool recurse)
|
||||
{
|
||||
ObjectProperty *prop, *next;
|
||||
int ret = 0;
|
||||
|
||||
QTAILQ_FOREACH_SAFE(prop, &obj->properties, node, next) {
|
||||
if (object_property_is_child(prop)) {
|
||||
ret = fn(prop->opaque, opaque);
|
||||
Object *child = prop->opaque;
|
||||
|
||||
ret = fn(child, opaque);
|
||||
if (ret != 0) {
|
||||
break;
|
||||
}
|
||||
if (recurse) {
|
||||
do_object_child_foreach(child, fn, opaque, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int object_child_foreach(Object *obj, int (*fn)(Object *child, void *opaque),
|
||||
void *opaque)
|
||||
{
|
||||
return do_object_child_foreach(obj, fn, opaque, false);
|
||||
}
|
||||
|
||||
int object_child_foreach_recursive(Object *obj,
|
||||
int (*fn)(Object *child, void *opaque),
|
||||
void *opaque)
|
||||
{
|
||||
return do_object_child_foreach(obj, fn, opaque, true);
|
||||
}
|
||||
|
||||
static void object_class_get_list_tramp(ObjectClass *klass, void *opaque)
|
||||
{
|
||||
GSList **list = opaque;
|
||||
|
|
|
@ -478,7 +478,8 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
|
|||
}
|
||||
|
||||
arm_log_exception(cs->exception_index);
|
||||
qemu_log_mask(CPU_LOG_INT, "...from EL%d\n", arm_current_el(env));
|
||||
qemu_log_mask(CPU_LOG_INT, "...from EL%d to EL%d\n", arm_current_el(env),
|
||||
new_el);
|
||||
if (qemu_loglevel_mask(CPU_LOG_INT)
|
||||
&& !excp_is_internal(cs->exception_index)) {
|
||||
qemu_log_mask(CPU_LOG_INT, "...with ESR 0x%" PRIx32 "\n",
|
||||
|
|
|
@ -2975,16 +2975,16 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
|
|||
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 3,
|
||||
.access = PL1_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 },
|
||||
{ .name = "AT_S12E1R", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 4,
|
||||
.opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 4,
|
||||
.access = PL2_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 },
|
||||
{ .name = "AT_S12E1W", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 5,
|
||||
.opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 5,
|
||||
.access = PL2_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 },
|
||||
{ .name = "AT_S12E0R", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 6,
|
||||
.opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 6,
|
||||
.access = PL2_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 },
|
||||
{ .name = "AT_S12E0W", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 7,
|
||||
.opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 7,
|
||||
.access = PL2_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 },
|
||||
/* AT S1E2* are elsewhere as they UNDEF from EL3 if EL2 is not present */
|
||||
{ .name = "AT_S1E3R", .state = ARM_CP_STATE_AA64,
|
||||
|
@ -2993,6 +2993,12 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
|
|||
{ .name = "AT_S1E3W", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 6, .crn = 7, .crm = 8, .opc2 = 1,
|
||||
.access = PL3_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 },
|
||||
{ .name = "PAR_EL1", .state = ARM_CP_STATE_AA64,
|
||||
.type = ARM_CP_ALIAS,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 7, .crm = 4, .opc2 = 0,
|
||||
.access = PL1_RW, .resetvalue = 0,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.par_el[1]),
|
||||
.writefn = par_write },
|
||||
#endif
|
||||
/* TLB invalidate last level of translation table walk */
|
||||
{ .name = "TLBIMVALIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 5,
|
||||
|
|
|
@ -10966,7 +10966,11 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu,
|
|||
dc->condjmp = 0;
|
||||
|
||||
dc->aarch64 = 1;
|
||||
dc->el3_is_aa64 = arm_el_is_aa64(env, 3);
|
||||
/* If we are coming from secure EL0 in a system with a 32-bit EL3, then
|
||||
* there is no secure EL1, so we route exceptions to EL3.
|
||||
*/
|
||||
dc->secure_routed_to_el3 = arm_feature(env, ARM_FEATURE_EL3) &&
|
||||
!arm_el_is_aa64(env, 3);
|
||||
dc->thumb = 0;
|
||||
dc->bswap_code = 0;
|
||||
dc->condexec_mask = 0;
|
||||
|
|
|
@ -11172,7 +11172,11 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
|
|||
dc->condjmp = 0;
|
||||
|
||||
dc->aarch64 = 0;
|
||||
dc->el3_is_aa64 = arm_el_is_aa64(env, 3);
|
||||
/* If we are coming from secure EL0 in a system with a 32-bit EL3, then
|
||||
* there is no secure EL1, so we route exceptions to EL3.
|
||||
*/
|
||||
dc->secure_routed_to_el3 = arm_feature(env, ARM_FEATURE_EL3) &&
|
||||
!arm_el_is_aa64(env, 3);
|
||||
dc->thumb = ARM_TBFLAG_THUMB(tb->flags);
|
||||
dc->bswap_code = ARM_TBFLAG_BSWAP_CODE(tb->flags);
|
||||
dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(tb->flags) & 0xf) << 1;
|
||||
|
|
|
@ -23,7 +23,8 @@ typedef struct DisasContext {
|
|||
ARMMMUIdx mmu_idx; /* MMU index to use for normal loads/stores */
|
||||
bool ns; /* Use non-secure CPREG bank on access */
|
||||
int fp_excp_el; /* FP exception EL or 0 if enabled */
|
||||
bool el3_is_aa64; /* Flag indicating whether EL3 is AArch64 or not */
|
||||
/* Flag indicating that exceptions from secure mode are routed to EL3. */
|
||||
bool secure_routed_to_el3;
|
||||
bool vfp_enabled; /* FP enabled via FPSCR.EN */
|
||||
int vec_len;
|
||||
int vec_stride;
|
||||
|
@ -84,7 +85,7 @@ static inline int default_exception_el(DisasContext *s)
|
|||
* exceptions can only be routed to ELs above 1, so we target the higher of
|
||||
* 1 or the current EL.
|
||||
*/
|
||||
return (s->mmu_idx == ARMMMUIdx_S1SE0 && !s->el3_is_aa64)
|
||||
return (s->mmu_idx == ARMMMUIdx_S1SE0 && s->secure_routed_to_el3)
|
||||
? 3 : MAX(1, s->current_el);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue