mirror of https://github.com/xemu-project/xemu.git
target-arm queue:
* mark MPS2/MPS3 board-internal i2c buses as 'full' so that command line user-created devices are not plugged into them * Take an exception if PSTATE.IL is set * Support an emulated ITS in the virt board * Add support for kudo-bmc board * Probe for KVM_CAP_ARM_VM_IPA_SIZE when creating scratch VM * cadence_uart: Fix clock handling issues that prevented u-boot from running -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmE/ruQZHHBldGVyLm1h eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3krdD/sHLxbPua1IOA1+uxLJwRnr N7BZa0GVNX8+dKi3w3jtYHOyFG1u9NeOp/VI93I7G9k0vRvYT8eMN4cMWwsaG5rr PPjiLIFAIFwxV9QkafIONLxLYFfc6T48tstG6BYaJU2tLPwIlSZK4ZbKqrxWesAm mMw75AtESjYI77yQcsEXDflmcvbvM++IrqQAa190i2D8rizbbv/gqZtzJJpU2OGy My51t+g1SPPJvoih6edpURGmKH1vmB0UwadnOG3GFv76c9nYeVPXAtdXS+8Rs+vU QJpvJ0MSRc5ZztsltvXQefH4aseSHrZybpZGI0tNpZ1G2oRwZHIXEMDcZwtRHKlZ o5M6oeNOUZFRFrLM8FRv4ErIFhgMwWUghy+oVejCF791j1WeasDpFL+ZZTWUNYiP qmNdh6z7Dt7F1fxBxMiCw9PTRNB2zudyz/ZtymPGYEDj7leIpQ/HudRmaDKZ+zMG A8omXNEw1LFsVrTE5MjLT7tr2Eq+71V2m0OkDB+Tvmpl4AXVG9b7kCoOp6NiAXZd Y4Vdi5I8NN3OHK0yO1vMxOlNk7qo4BTqT7FYaSb1qaTZ/6TQtrWb7ThU989JJaQE 28H1p8uezMDC8NsaEBa2eBsen6Uf45jYKxgUpG0jB9QuXtRY1xUdaU06fQlz4dpn 7SyfLZbzeB0v+Bqd7z3Y9A== =7BH/ -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20210913-3' into staging target-arm queue: * mark MPS2/MPS3 board-internal i2c buses as 'full' so that command line user-created devices are not plugged into them * Take an exception if PSTATE.IL is set * Support an emulated ITS in the virt board * Add support for kudo-bmc board * Probe for KVM_CAP_ARM_VM_IPA_SIZE when creating scratch VM * cadence_uart: Fix clock handling issues that prevented u-boot from running # gpg: Signature made Mon 13 Sep 2021 21:04:52 BST # 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-20210913-3: (23 commits) hw/arm/mps2.c: Mark internal-only I2C buses as 'full' hw/arm/mps2-tz.c: Mark internal-only I2C buses as 'full' hw/arm/mps2-tz.c: Add extra data parameter to MakeDevFn qdev: Support marking individual buses as 'full' target/arm: Merge disas_a64_insn into aarch64_tr_translate_insn target/arm: Take an exception if PSTATE.IL is set tests/data/acpi/virt: Update IORT files for ITS hw/arm/virt: add ITS support in virt GIC tests/data/acpi/virt: Add IORT files for ITS hw/intc: GICv3 redistributor ITS processing hw/intc: GICv3 ITS Feature enablement hw/intc: GICv3 ITS Command processing hw/intc: GICv3 ITS command queue framework hw/intc: GICv3 ITS register definitions added hw/intc: GICv3 ITS initial framework hw/arm: Add support for kudo-bmc board. hw/arm/virt: KVM: Probe for KVM_CAP_ARM_VM_IPA_SIZE when creating scratch VM hw/char: cadence_uart: Log a guest error when device is unclocked or in reset hw/char: cadence_uart: Ignore access when unclocked or in reset for uart_{read, write}() hw/char: cadence_uart: Convert to memop_with_attrs() ops ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
c6f5e042d8
|
@ -20,6 +20,7 @@ Hyperscale applications. The following machines are based on this chip :
|
|||
|
||||
- ``quanta-gbs-bmc`` Quanta GBS server BMC
|
||||
- ``quanta-gsj`` Quanta GSJ server BMC
|
||||
- ``kudo-bmc`` Fii USA Kudo server BMC
|
||||
|
||||
There are also two more SoCs, NPCM710 and NPCM705, which are single-core
|
||||
variants of NPCM750 and NPCM730, respectively. These are currently not
|
||||
|
|
|
@ -373,6 +373,11 @@ static qemu_irq get_sse_irq_in(MPS2TZMachineState *mms, int irqno)
|
|||
}
|
||||
}
|
||||
|
||||
/* Union describing the device-specific extra data we pass to the devfn. */
|
||||
typedef union PPCExtraData {
|
||||
bool i2c_internal;
|
||||
} PPCExtraData;
|
||||
|
||||
/* Most of the devices in the AN505 FPGA image sit behind
|
||||
* Peripheral Protection Controllers. These data structures
|
||||
* define the layout of which devices sit behind which PPCs.
|
||||
|
@ -382,7 +387,8 @@ static qemu_irq get_sse_irq_in(MPS2TZMachineState *mms, int irqno)
|
|||
*/
|
||||
typedef MemoryRegion *MakeDevFn(MPS2TZMachineState *mms, void *opaque,
|
||||
const char *name, hwaddr size,
|
||||
const int *irqs);
|
||||
const int *irqs,
|
||||
const PPCExtraData *extradata);
|
||||
|
||||
typedef struct PPCPortInfo {
|
||||
const char *name;
|
||||
|
@ -391,6 +397,7 @@ typedef struct PPCPortInfo {
|
|||
hwaddr addr;
|
||||
hwaddr size;
|
||||
int irqs[3]; /* currently no device needs more IRQ lines than this */
|
||||
PPCExtraData extradata; /* to pass device-specific info to the devfn */
|
||||
} PPCPortInfo;
|
||||
|
||||
typedef struct PPCInfo {
|
||||
|
@ -401,7 +408,8 @@ typedef struct PPCInfo {
|
|||
static MemoryRegion *make_unimp_dev(MPS2TZMachineState *mms,
|
||||
void *opaque,
|
||||
const char *name, hwaddr size,
|
||||
const int *irqs)
|
||||
const int *irqs,
|
||||
const PPCExtraData *extradata)
|
||||
{
|
||||
/* Initialize, configure and realize a TYPE_UNIMPLEMENTED_DEVICE,
|
||||
* and return a pointer to its MemoryRegion.
|
||||
|
@ -417,7 +425,7 @@ static MemoryRegion *make_unimp_dev(MPS2TZMachineState *mms,
|
|||
|
||||
static MemoryRegion *make_uart(MPS2TZMachineState *mms, void *opaque,
|
||||
const char *name, hwaddr size,
|
||||
const int *irqs)
|
||||
const int *irqs, const PPCExtraData *extradata)
|
||||
{
|
||||
/* The irq[] array is tx, rx, combined, in that order */
|
||||
MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms);
|
||||
|
@ -441,7 +449,7 @@ static MemoryRegion *make_uart(MPS2TZMachineState *mms, void *opaque,
|
|||
|
||||
static MemoryRegion *make_scc(MPS2TZMachineState *mms, void *opaque,
|
||||
const char *name, hwaddr size,
|
||||
const int *irqs)
|
||||
const int *irqs, const PPCExtraData *extradata)
|
||||
{
|
||||
MPS2SCC *scc = opaque;
|
||||
DeviceState *sccdev;
|
||||
|
@ -465,7 +473,7 @@ static MemoryRegion *make_scc(MPS2TZMachineState *mms, void *opaque,
|
|||
|
||||
static MemoryRegion *make_fpgaio(MPS2TZMachineState *mms, void *opaque,
|
||||
const char *name, hwaddr size,
|
||||
const int *irqs)
|
||||
const int *irqs, const PPCExtraData *extradata)
|
||||
{
|
||||
MPS2FPGAIO *fpgaio = opaque;
|
||||
MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms);
|
||||
|
@ -480,7 +488,8 @@ static MemoryRegion *make_fpgaio(MPS2TZMachineState *mms, void *opaque,
|
|||
|
||||
static MemoryRegion *make_eth_dev(MPS2TZMachineState *mms, void *opaque,
|
||||
const char *name, hwaddr size,
|
||||
const int *irqs)
|
||||
const int *irqs,
|
||||
const PPCExtraData *extradata)
|
||||
{
|
||||
SysBusDevice *s;
|
||||
NICInfo *nd = &nd_table[0];
|
||||
|
@ -500,7 +509,8 @@ static MemoryRegion *make_eth_dev(MPS2TZMachineState *mms, void *opaque,
|
|||
|
||||
static MemoryRegion *make_eth_usb(MPS2TZMachineState *mms, void *opaque,
|
||||
const char *name, hwaddr size,
|
||||
const int *irqs)
|
||||
const int *irqs,
|
||||
const PPCExtraData *extradata)
|
||||
{
|
||||
/*
|
||||
* The AN524 makes the ethernet and USB share a PPC port.
|
||||
|
@ -543,7 +553,7 @@ static MemoryRegion *make_eth_usb(MPS2TZMachineState *mms, void *opaque,
|
|||
|
||||
static MemoryRegion *make_mpc(MPS2TZMachineState *mms, void *opaque,
|
||||
const char *name, hwaddr size,
|
||||
const int *irqs)
|
||||
const int *irqs, const PPCExtraData *extradata)
|
||||
{
|
||||
TZMPC *mpc = opaque;
|
||||
int i = mpc - &mms->mpc[0];
|
||||
|
@ -615,7 +625,7 @@ static void remap_irq_fn(void *opaque, int n, int level)
|
|||
|
||||
static MemoryRegion *make_dma(MPS2TZMachineState *mms, void *opaque,
|
||||
const char *name, hwaddr size,
|
||||
const int *irqs)
|
||||
const int *irqs, const PPCExtraData *extradata)
|
||||
{
|
||||
/* The irq[] array is DMACINTR, DMACINTERR, DMACINTTC, in that order */
|
||||
PL080State *dma = opaque;
|
||||
|
@ -672,7 +682,7 @@ static MemoryRegion *make_dma(MPS2TZMachineState *mms, void *opaque,
|
|||
|
||||
static MemoryRegion *make_spi(MPS2TZMachineState *mms, void *opaque,
|
||||
const char *name, hwaddr size,
|
||||
const int *irqs)
|
||||
const int *irqs, const PPCExtraData *extradata)
|
||||
{
|
||||
/*
|
||||
* The AN505 has five PL022 SPI controllers.
|
||||
|
@ -694,7 +704,7 @@ static MemoryRegion *make_spi(MPS2TZMachineState *mms, void *opaque,
|
|||
|
||||
static MemoryRegion *make_i2c(MPS2TZMachineState *mms, void *opaque,
|
||||
const char *name, hwaddr size,
|
||||
const int *irqs)
|
||||
const int *irqs, const PPCExtraData *extradata)
|
||||
{
|
||||
ArmSbconI2CState *i2c = opaque;
|
||||
SysBusDevice *s;
|
||||
|
@ -702,12 +712,26 @@ static MemoryRegion *make_i2c(MPS2TZMachineState *mms, void *opaque,
|
|||
object_initialize_child(OBJECT(mms), name, i2c, TYPE_ARM_SBCON_I2C);
|
||||
s = SYS_BUS_DEVICE(i2c);
|
||||
sysbus_realize(s, &error_fatal);
|
||||
|
||||
/*
|
||||
* If this is an internal-use-only i2c bus, mark it full
|
||||
* so that user-created i2c devices are not plugged into it.
|
||||
* If we implement models of any on-board i2c devices that
|
||||
* plug in to one of the internal-use-only buses, then we will
|
||||
* need to create and plugging those in here before we mark the
|
||||
* bus as full.
|
||||
*/
|
||||
if (extradata->i2c_internal) {
|
||||
BusState *qbus = qdev_get_child_bus(DEVICE(i2c), "i2c");
|
||||
qbus_mark_full(qbus);
|
||||
}
|
||||
|
||||
return sysbus_mmio_get_region(s, 0);
|
||||
}
|
||||
|
||||
static MemoryRegion *make_rtc(MPS2TZMachineState *mms, void *opaque,
|
||||
const char *name, hwaddr size,
|
||||
const int *irqs)
|
||||
const int *irqs, const PPCExtraData *extradata)
|
||||
{
|
||||
PL031State *pl031 = opaque;
|
||||
SysBusDevice *s;
|
||||
|
@ -912,10 +936,14 @@ static void mps2tz_common_init(MachineState *machine)
|
|||
{ "uart2", make_uart, &mms->uart[2], 0x40202000, 0x1000, { 36, 37, 44 } },
|
||||
{ "uart3", make_uart, &mms->uart[3], 0x40203000, 0x1000, { 38, 39, 45 } },
|
||||
{ "uart4", make_uart, &mms->uart[4], 0x40204000, 0x1000, { 40, 41, 46 } },
|
||||
{ "i2c0", make_i2c, &mms->i2c[0], 0x40207000, 0x1000 },
|
||||
{ "i2c1", make_i2c, &mms->i2c[1], 0x40208000, 0x1000 },
|
||||
{ "i2c2", make_i2c, &mms->i2c[2], 0x4020c000, 0x1000 },
|
||||
{ "i2c3", make_i2c, &mms->i2c[3], 0x4020d000, 0x1000 },
|
||||
{ "i2c0", make_i2c, &mms->i2c[0], 0x40207000, 0x1000, {},
|
||||
{ .i2c_internal = true /* touchscreen */ } },
|
||||
{ "i2c1", make_i2c, &mms->i2c[1], 0x40208000, 0x1000, {},
|
||||
{ .i2c_internal = true /* audio conf */ } },
|
||||
{ "i2c2", make_i2c, &mms->i2c[2], 0x4020c000, 0x1000, {},
|
||||
{ .i2c_internal = false /* shield 0 */ } },
|
||||
{ "i2c3", make_i2c, &mms->i2c[3], 0x4020d000, 0x1000, {},
|
||||
{ .i2c_internal = false /* shield 1 */ } },
|
||||
},
|
||||
}, {
|
||||
.name = "apb_ppcexp2",
|
||||
|
@ -956,15 +984,20 @@ static void mps2tz_common_init(MachineState *machine)
|
|||
}, {
|
||||
.name = "apb_ppcexp1",
|
||||
.ports = {
|
||||
{ "i2c0", make_i2c, &mms->i2c[0], 0x41200000, 0x1000 },
|
||||
{ "i2c1", make_i2c, &mms->i2c[1], 0x41201000, 0x1000 },
|
||||
{ "i2c0", make_i2c, &mms->i2c[0], 0x41200000, 0x1000, {},
|
||||
{ .i2c_internal = true /* touchscreen */ } },
|
||||
{ "i2c1", make_i2c, &mms->i2c[1], 0x41201000, 0x1000, {},
|
||||
{ .i2c_internal = true /* audio conf */ } },
|
||||
{ "spi0", make_spi, &mms->spi[0], 0x41202000, 0x1000, { 52 } },
|
||||
{ "spi1", make_spi, &mms->spi[1], 0x41203000, 0x1000, { 53 } },
|
||||
{ "spi2", make_spi, &mms->spi[2], 0x41204000, 0x1000, { 54 } },
|
||||
{ "i2c2", make_i2c, &mms->i2c[2], 0x41205000, 0x1000 },
|
||||
{ "i2c3", make_i2c, &mms->i2c[3], 0x41206000, 0x1000 },
|
||||
{ "i2c2", make_i2c, &mms->i2c[2], 0x41205000, 0x1000, {},
|
||||
{ .i2c_internal = false /* shield 0 */ } },
|
||||
{ "i2c3", make_i2c, &mms->i2c[3], 0x41206000, 0x1000, {},
|
||||
{ .i2c_internal = false /* shield 1 */ } },
|
||||
{ /* port 7 reserved */ },
|
||||
{ "i2c4", make_i2c, &mms->i2c[4], 0x41208000, 0x1000 },
|
||||
{ "i2c4", make_i2c, &mms->i2c[4], 0x41208000, 0x1000, {},
|
||||
{ .i2c_internal = true /* DDR4 EEPROM */ } },
|
||||
},
|
||||
}, {
|
||||
.name = "apb_ppcexp2",
|
||||
|
@ -1006,15 +1039,20 @@ static void mps2tz_common_init(MachineState *machine)
|
|||
}, {
|
||||
.name = "apb_ppcexp1",
|
||||
.ports = {
|
||||
{ "i2c0", make_i2c, &mms->i2c[0], 0x49200000, 0x1000 },
|
||||
{ "i2c1", make_i2c, &mms->i2c[1], 0x49201000, 0x1000 },
|
||||
{ "i2c0", make_i2c, &mms->i2c[0], 0x49200000, 0x1000, {},
|
||||
{ .i2c_internal = true /* touchscreen */ } },
|
||||
{ "i2c1", make_i2c, &mms->i2c[1], 0x49201000, 0x1000, {},
|
||||
{ .i2c_internal = true /* audio conf */ } },
|
||||
{ "spi0", make_spi, &mms->spi[0], 0x49202000, 0x1000, { 53 } },
|
||||
{ "spi1", make_spi, &mms->spi[1], 0x49203000, 0x1000, { 54 } },
|
||||
{ "spi2", make_spi, &mms->spi[2], 0x49204000, 0x1000, { 55 } },
|
||||
{ "i2c2", make_i2c, &mms->i2c[2], 0x49205000, 0x1000 },
|
||||
{ "i2c3", make_i2c, &mms->i2c[3], 0x49206000, 0x1000 },
|
||||
{ "i2c2", make_i2c, &mms->i2c[2], 0x49205000, 0x1000, {},
|
||||
{ .i2c_internal = false /* shield 0 */ } },
|
||||
{ "i2c3", make_i2c, &mms->i2c[3], 0x49206000, 0x1000, {},
|
||||
{ .i2c_internal = false /* shield 1 */ } },
|
||||
{ /* port 7 reserved */ },
|
||||
{ "i2c4", make_i2c, &mms->i2c[4], 0x49208000, 0x1000 },
|
||||
{ "i2c4", make_i2c, &mms->i2c[4], 0x49208000, 0x1000, {},
|
||||
{ .i2c_internal = true /* DDR4 EEPROM */ } },
|
||||
},
|
||||
}, {
|
||||
.name = "apb_ppcexp2",
|
||||
|
@ -1084,7 +1122,7 @@ static void mps2tz_common_init(MachineState *machine)
|
|||
}
|
||||
|
||||
mr = pinfo->devfn(mms, pinfo->opaque, pinfo->name, pinfo->size,
|
||||
pinfo->irqs);
|
||||
pinfo->irqs, &pinfo->extradata);
|
||||
portname = g_strdup_printf("port[%d]", port);
|
||||
object_property_set_link(OBJECT(ppc), portname, OBJECT(mr),
|
||||
&error_fatal);
|
||||
|
|
|
@ -428,7 +428,17 @@ static void mps2_common_init(MachineState *machine)
|
|||
0x40023000, /* Audio */
|
||||
0x40029000, /* Shield0 */
|
||||
0x4002a000}; /* Shield1 */
|
||||
sysbus_create_simple(TYPE_ARM_SBCON_I2C, i2cbase[i], NULL);
|
||||
DeviceState *dev;
|
||||
|
||||
dev = sysbus_create_simple(TYPE_ARM_SBCON_I2C, i2cbase[i], NULL);
|
||||
if (i < 2) {
|
||||
/*
|
||||
* internal-only bus: mark it full to avoid user-created
|
||||
* i2c devices being plugged into it.
|
||||
*/
|
||||
BusState *qbus = qdev_get_child_bus(dev, "i2c");
|
||||
qbus_mark_full(qbus);
|
||||
}
|
||||
}
|
||||
create_unimplemented_device("i2s", 0x40024000, 0x400);
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#define NPCM750_EVB_POWER_ON_STRAPS 0x00001ff7
|
||||
#define QUANTA_GSJ_POWER_ON_STRAPS 0x00001fff
|
||||
#define QUANTA_GBS_POWER_ON_STRAPS 0x000017ff
|
||||
#define KUDO_BMC_POWER_ON_STRAPS 0x00001fff
|
||||
|
||||
static const char npcm7xx_default_bootrom[] = "npcm7xx_bootrom.bin";
|
||||
|
||||
|
@ -357,6 +358,23 @@ static void quanta_gbs_init(MachineState *machine)
|
|||
npcm7xx_load_kernel(machine, soc);
|
||||
}
|
||||
|
||||
static void kudo_bmc_init(MachineState *machine)
|
||||
{
|
||||
NPCM7xxState *soc;
|
||||
|
||||
soc = npcm7xx_create_soc(machine, KUDO_BMC_POWER_ON_STRAPS);
|
||||
npcm7xx_connect_dram(soc, machine->ram);
|
||||
qdev_realize(DEVICE(soc), NULL, &error_fatal);
|
||||
|
||||
npcm7xx_load_bootrom(machine, soc);
|
||||
npcm7xx_connect_flash(&soc->fiu[0], 0, "mx66u51235f",
|
||||
drive_get(IF_MTD, 0, 0));
|
||||
npcm7xx_connect_flash(&soc->fiu[1], 0, "mx66u51235f",
|
||||
drive_get(IF_MTD, 3, 0));
|
||||
|
||||
npcm7xx_load_kernel(machine, soc);
|
||||
}
|
||||
|
||||
static void npcm7xx_set_soc_type(NPCM7xxMachineClass *nmc, const char *type)
|
||||
{
|
||||
NPCM7xxClass *sc = NPCM7XX_CLASS(object_class_by_name(type));
|
||||
|
@ -417,6 +435,18 @@ static void gbs_bmc_machine_class_init(ObjectClass *oc, void *data)
|
|||
mc->default_ram_size = 1 * GiB;
|
||||
}
|
||||
|
||||
static void kudo_bmc_machine_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_CLASS(oc);
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
npcm7xx_set_soc_type(nmc, TYPE_NPCM730);
|
||||
|
||||
mc->desc = "Kudo BMC (Cortex-A9)";
|
||||
mc->init = kudo_bmc_init;
|
||||
mc->default_ram_size = 1 * GiB;
|
||||
};
|
||||
|
||||
static const TypeInfo npcm7xx_machine_types[] = {
|
||||
{
|
||||
.name = TYPE_NPCM7XX_MACHINE,
|
||||
|
@ -437,6 +467,10 @@ static const TypeInfo npcm7xx_machine_types[] = {
|
|||
.name = MACHINE_TYPE_NAME("quanta-gbs-bmc"),
|
||||
.parent = TYPE_NPCM7XX_MACHINE,
|
||||
.class_init = gbs_bmc_machine_class_init,
|
||||
}, {
|
||||
.name = MACHINE_TYPE_NAME("kudo-bmc"),
|
||||
.parent = TYPE_NPCM7XX_MACHINE,
|
||||
.class_init = kudo_bmc_machine_class_init,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -584,6 +584,12 @@ static void create_its(VirtMachineState *vms)
|
|||
const char *itsclass = its_class_name();
|
||||
DeviceState *dev;
|
||||
|
||||
if (!strcmp(itsclass, "arm-gicv3-its")) {
|
||||
if (!vms->tcg_its) {
|
||||
itsclass = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!itsclass) {
|
||||
/* Do nothing if not supported */
|
||||
return;
|
||||
|
@ -621,7 +627,7 @@ static void create_v2m(VirtMachineState *vms)
|
|||
vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
|
||||
}
|
||||
|
||||
static void create_gic(VirtMachineState *vms)
|
||||
static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
|
||||
{
|
||||
MachineState *ms = MACHINE(vms);
|
||||
/* We create a standalone GIC */
|
||||
|
@ -655,6 +661,14 @@ static void create_gic(VirtMachineState *vms)
|
|||
nb_redist_regions);
|
||||
qdev_prop_set_uint32(vms->gic, "redist-region-count[0]", redist0_count);
|
||||
|
||||
if (!kvm_irqchip_in_kernel()) {
|
||||
if (vms->tcg_its) {
|
||||
object_property_set_link(OBJECT(vms->gic), "sysmem",
|
||||
OBJECT(mem), &error_fatal);
|
||||
qdev_prop_set_bit(vms->gic, "has-lpi", true);
|
||||
}
|
||||
}
|
||||
|
||||
if (nb_redist_regions == 2) {
|
||||
uint32_t redist1_capacity =
|
||||
vms->memmap[VIRT_HIGH_GIC_REDIST2].size / GICV3_REDIST_SIZE;
|
||||
|
@ -2039,7 +2053,7 @@ static void machvirt_init(MachineState *machine)
|
|||
|
||||
virt_flash_fdt(vms, sysmem, secure_sysmem ?: sysmem);
|
||||
|
||||
create_gic(vms);
|
||||
create_gic(vms, sysmem);
|
||||
|
||||
virt_cpu_post_init(vms, sysmem);
|
||||
|
||||
|
@ -2742,6 +2756,12 @@ static void virt_instance_init(Object *obj)
|
|||
} else {
|
||||
/* Default allows ITS instantiation */
|
||||
vms->its = true;
|
||||
|
||||
if (vmc->no_tcg_its) {
|
||||
vms->tcg_its = false;
|
||||
} else {
|
||||
vms->tcg_its = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Default disallows iommu instantiation */
|
||||
|
@ -2791,8 +2811,13 @@ DEFINE_VIRT_MACHINE_AS_LATEST(6, 2)
|
|||
|
||||
static void virt_machine_6_1_options(MachineClass *mc)
|
||||
{
|
||||
VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
|
||||
|
||||
virt_machine_6_2_options(mc);
|
||||
compat_props_add(mc->compat_props, hw_compat_6_1, hw_compat_6_1_len);
|
||||
|
||||
/* qemu ITS was introduced with 6.2 */
|
||||
vmc->no_tcg_its = true;
|
||||
}
|
||||
DEFINE_VIRT_MACHINE(6, 1)
|
||||
|
||||
|
|
|
@ -235,8 +235,18 @@ static void uart_parameters_setup(CadenceUARTState *s)
|
|||
static int uart_can_receive(void *opaque)
|
||||
{
|
||||
CadenceUARTState *s = opaque;
|
||||
int ret = MAX(CADENCE_UART_RX_FIFO_SIZE, CADENCE_UART_TX_FIFO_SIZE);
|
||||
uint32_t ch_mode = s->r[R_MR] & UART_MR_CHMODE;
|
||||
int ret;
|
||||
uint32_t ch_mode;
|
||||
|
||||
/* ignore characters when unclocked or in reset */
|
||||
if (!clock_is_enabled(s->refclk) || device_is_in_reset(DEVICE(s))) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: uart is unclocked or in reset\n",
|
||||
__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = MAX(CADENCE_UART_RX_FIFO_SIZE, CADENCE_UART_TX_FIFO_SIZE);
|
||||
ch_mode = s->r[R_MR] & UART_MR_CHMODE;
|
||||
|
||||
if (ch_mode == NORMAL_MODE || ch_mode == ECHO_MODE) {
|
||||
ret = MIN(ret, CADENCE_UART_RX_FIFO_SIZE - s->rx_count);
|
||||
|
@ -353,11 +363,6 @@ static void uart_receive(void *opaque, const uint8_t *buf, int size)
|
|||
CadenceUARTState *s = opaque;
|
||||
uint32_t ch_mode = s->r[R_MR] & UART_MR_CHMODE;
|
||||
|
||||
/* ignore characters when unclocked or in reset */
|
||||
if (!clock_is_enabled(s->refclk) || device_is_in_reset(DEVICE(s))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ch_mode == NORMAL_MODE || ch_mode == ECHO_MODE) {
|
||||
uart_write_rx_fifo(opaque, buf, size);
|
||||
}
|
||||
|
@ -373,6 +378,8 @@ static void uart_event(void *opaque, QEMUChrEvent event)
|
|||
|
||||
/* ignore characters when unclocked or in reset */
|
||||
if (!clock_is_enabled(s->refclk) || device_is_in_reset(DEVICE(s))) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: uart is unclocked or in reset\n",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -403,15 +410,22 @@ static void uart_read_rx_fifo(CadenceUARTState *s, uint32_t *c)
|
|||
uart_update_status(s);
|
||||
}
|
||||
|
||||
static void uart_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
static MemTxResult uart_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size, MemTxAttrs attrs)
|
||||
{
|
||||
CadenceUARTState *s = opaque;
|
||||
|
||||
/* ignore access when unclocked or in reset */
|
||||
if (!clock_is_enabled(s->refclk) || device_is_in_reset(DEVICE(s))) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: uart is unclocked or in reset\n",
|
||||
__func__);
|
||||
return MEMTX_ERROR;
|
||||
}
|
||||
|
||||
DB_PRINT(" offset:%x data:%08x\n", (unsigned)offset, (unsigned)value);
|
||||
offset >>= 2;
|
||||
if (offset >= CADENCE_UART_R_MAX) {
|
||||
return;
|
||||
return MEMTX_DECODE_ERROR;
|
||||
}
|
||||
switch (offset) {
|
||||
case R_IER: /* ier (wts imr) */
|
||||
|
@ -458,30 +472,41 @@ static void uart_write(void *opaque, hwaddr offset,
|
|||
break;
|
||||
}
|
||||
uart_update_status(s);
|
||||
|
||||
return MEMTX_OK;
|
||||
}
|
||||
|
||||
static uint64_t uart_read(void *opaque, hwaddr offset,
|
||||
unsigned size)
|
||||
static MemTxResult uart_read(void *opaque, hwaddr offset,
|
||||
uint64_t *value, unsigned size, MemTxAttrs attrs)
|
||||
{
|
||||
CadenceUARTState *s = opaque;
|
||||
uint32_t c = 0;
|
||||
|
||||
/* ignore access when unclocked or in reset */
|
||||
if (!clock_is_enabled(s->refclk) || device_is_in_reset(DEVICE(s))) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: uart is unclocked or in reset\n",
|
||||
__func__);
|
||||
return MEMTX_ERROR;
|
||||
}
|
||||
|
||||
offset >>= 2;
|
||||
if (offset >= CADENCE_UART_R_MAX) {
|
||||
c = 0;
|
||||
} else if (offset == R_TX_RX) {
|
||||
return MEMTX_DECODE_ERROR;
|
||||
}
|
||||
if (offset == R_TX_RX) {
|
||||
uart_read_rx_fifo(s, &c);
|
||||
} else {
|
||||
c = s->r[offset];
|
||||
c = s->r[offset];
|
||||
}
|
||||
|
||||
DB_PRINT(" offset:%x data:%08x\n", (unsigned)(offset << 2), (unsigned)c);
|
||||
return c;
|
||||
*value = c;
|
||||
return MEMTX_OK;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps uart_ops = {
|
||||
.read = uart_read,
|
||||
.write = uart_write,
|
||||
.read_with_attrs = uart_read,
|
||||
.write_with_attrs = uart_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
|
|
|
@ -165,6 +165,16 @@ static void gicv3_redist_update_noirqset(GICv3CPUState *cs)
|
|||
cs->hppi.grp = gicv3_irq_group(cs->gic, cs, cs->hppi.irq);
|
||||
}
|
||||
|
||||
if ((cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) && cs->gic->lpi_enable &&
|
||||
(cs->hpplpi.prio != 0xff)) {
|
||||
if (irqbetter(cs, cs->hpplpi.irq, cs->hpplpi.prio)) {
|
||||
cs->hppi.irq = cs->hpplpi.irq;
|
||||
cs->hppi.prio = cs->hpplpi.prio;
|
||||
cs->hppi.grp = cs->hpplpi.grp;
|
||||
seenbetter = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the best interrupt we just found would preempt whatever
|
||||
* was the previous best interrupt before this update, then
|
||||
* we know it's definitely the best one now.
|
||||
|
@ -339,9 +349,13 @@ static void gicv3_set_irq(void *opaque, int irq, int level)
|
|||
|
||||
static void arm_gicv3_post_load(GICv3State *s)
|
||||
{
|
||||
int i;
|
||||
/* Recalculate our cached idea of the current highest priority
|
||||
* pending interrupt, but don't set IRQ or FIQ lines.
|
||||
*/
|
||||
for (i = 0; i < s->num_cpu; i++) {
|
||||
gicv3_redist_update_lpi(&s->cpu[i]);
|
||||
}
|
||||
gicv3_full_update_noirqset(s);
|
||||
/* Repopulate the cache of GICv3CPUState pointers for target CPUs */
|
||||
gicv3_cache_all_target_cpustates(s);
|
||||
|
|
|
@ -345,6 +345,11 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
|
|||
return;
|
||||
}
|
||||
|
||||
if (s->lpi_enable && !s->dma) {
|
||||
error_setg(errp, "Redist-ITS: Guest 'sysmem' reference link not set");
|
||||
return;
|
||||
}
|
||||
|
||||
s->cpu = g_new0(GICv3CPUState, s->num_cpu);
|
||||
|
||||
for (i = 0; i < s->num_cpu; i++) {
|
||||
|
@ -381,6 +386,10 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
|
|||
(1 << 24) |
|
||||
(i << 8) |
|
||||
(last << 4);
|
||||
|
||||
if (s->lpi_enable) {
|
||||
s->cpu[i].gicr_typer |= GICR_TYPER_PLPIS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -426,6 +435,7 @@ static void arm_gicv3_common_reset(DeviceState *dev)
|
|||
memset(cs->gicr_ipriorityr, 0, sizeof(cs->gicr_ipriorityr));
|
||||
|
||||
cs->hppi.prio = 0xff;
|
||||
cs->hpplpi.prio = 0xff;
|
||||
|
||||
/* State in the CPU interface must *not* be reset here, because it
|
||||
* is part of the CPU's reset domain, not the GIC device's.
|
||||
|
@ -494,9 +504,12 @@ static Property arm_gicv3_common_properties[] = {
|
|||
DEFINE_PROP_UINT32("num-cpu", GICv3State, num_cpu, 1),
|
||||
DEFINE_PROP_UINT32("num-irq", GICv3State, num_irq, 32),
|
||||
DEFINE_PROP_UINT32("revision", GICv3State, revision, 3),
|
||||
DEFINE_PROP_BOOL("has-lpi", GICv3State, lpi_enable, 0),
|
||||
DEFINE_PROP_BOOL("has-security-extensions", GICv3State, security_extn, 0),
|
||||
DEFINE_PROP_ARRAY("redist-region-count", GICv3State, nb_redist_regions,
|
||||
redist_region_count, qdev_prop_uint32, uint32_t),
|
||||
DEFINE_PROP_LINK("sysmem", GICv3State, dma, TYPE_MEMORY_REGION,
|
||||
MemoryRegion *),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
|
|
@ -899,10 +899,12 @@ static void icc_activate_irq(GICv3CPUState *cs, int irq)
|
|||
cs->gicr_iactiver0 = deposit32(cs->gicr_iactiver0, irq, 1, 1);
|
||||
cs->gicr_ipendr0 = deposit32(cs->gicr_ipendr0, irq, 1, 0);
|
||||
gicv3_redist_update(cs);
|
||||
} else {
|
||||
} else if (irq < GICV3_LPI_INTID_START) {
|
||||
gicv3_gicd_active_set(cs->gic, irq);
|
||||
gicv3_gicd_pending_clear(cs->gic, irq);
|
||||
gicv3_update(cs->gic, irq, 1);
|
||||
} else {
|
||||
gicv3_redist_lpi_pending(cs, irq, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1318,7 +1320,8 @@ static void icc_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
trace_gicv3_icc_eoir_write(is_eoir0 ? 0 : 1,
|
||||
gicv3_redist_affid(cs), value);
|
||||
|
||||
if (irq >= cs->gic->num_irq) {
|
||||
if ((irq >= cs->gic->num_irq) &&
|
||||
!(cs->gic->lpi_enable && (irq >= GICV3_LPI_INTID_START))) {
|
||||
/* This handles two cases:
|
||||
* 1. If software writes the ID of a spurious interrupt [ie 1020-1023]
|
||||
* to the GICC_EOIR, the GIC ignores that write.
|
||||
|
|
|
@ -384,7 +384,9 @@ static bool gicd_readl(GICv3State *s, hwaddr offset,
|
|||
* A3V == 1 (non-zero values of Affinity level 3 supported)
|
||||
* IDbits == 0xf (we support 16-bit interrupt identifiers)
|
||||
* DVIS == 0 (Direct virtual LPI injection not supported)
|
||||
* LPIS == 0 (LPIs not supported)
|
||||
* LPIS == 1 (LPIs are supported if affinity routing is enabled)
|
||||
* num_LPIs == 0b00000 (bits [15:11],Number of LPIs as indicated
|
||||
* by GICD_TYPER.IDbits)
|
||||
* MBIS == 0 (message-based SPIs not supported)
|
||||
* SecurityExtn == 1 if security extns supported
|
||||
* CPUNumber == 0 since for us ARE is always 1
|
||||
|
@ -399,6 +401,7 @@ static bool gicd_readl(GICv3State *s, hwaddr offset,
|
|||
bool sec_extn = !(s->gicd_ctlr & GICD_CTLR_DS);
|
||||
|
||||
*data = (1 << 25) | (1 << 24) | (sec_extn << 10) |
|
||||
(s->lpi_enable << GICD_TYPER_LPIS_SHIFT) |
|
||||
(0xf << 19) | itlinesnumber;
|
||||
return true;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -50,6 +50,8 @@ static int gicv3_its_post_load(void *opaque, int version_id)
|
|||
|
||||
static const VMStateDescription vmstate_its = {
|
||||
.name = "arm_gicv3_its",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.pre_save = gicv3_its_pre_save,
|
||||
.post_load = gicv3_its_post_load,
|
||||
.priority = MIG_PRI_GICV3_ITS,
|
||||
|
@ -99,14 +101,15 @@ static const MemoryRegionOps gicv3_its_trans_ops = {
|
|||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
void gicv3_its_init_mmio(GICv3ITSState *s, const MemoryRegionOps *ops)
|
||||
void gicv3_its_init_mmio(GICv3ITSState *s, const MemoryRegionOps *ops,
|
||||
const MemoryRegionOps *tops)
|
||||
{
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(s);
|
||||
|
||||
memory_region_init_io(&s->iomem_its_cntrl, OBJECT(s), ops, s,
|
||||
"control", ITS_CONTROL_SIZE);
|
||||
memory_region_init_io(&s->iomem_its_translation, OBJECT(s),
|
||||
&gicv3_its_trans_ops, s,
|
||||
tops ? tops : &gicv3_its_trans_ops, s,
|
||||
"translation", ITS_TRANS_SIZE);
|
||||
|
||||
/* Our two regions are always adjacent, therefore we now combine them
|
||||
|
|
|
@ -106,7 +106,7 @@ static void kvm_arm_its_realize(DeviceState *dev, Error **errp)
|
|||
kvm_arm_register_device(&s->iomem_its_cntrl, -1, KVM_DEV_ARM_VGIC_GRP_ADDR,
|
||||
KVM_VGIC_ITS_ADDR_TYPE, s->dev_fd, 0);
|
||||
|
||||
gicv3_its_init_mmio(s, NULL);
|
||||
gicv3_its_init_mmio(s, NULL, NULL);
|
||||
|
||||
if (!kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
|
||||
GITS_CTLR)) {
|
||||
|
|
|
@ -248,10 +248,19 @@ static MemTxResult gicr_writel(GICv3CPUState *cs, hwaddr offset,
|
|||
case GICR_CTLR:
|
||||
/* For our implementation, GICR_TYPER.DPGS is 0 and so all
|
||||
* the DPG bits are RAZ/WI. We don't do anything asynchronously,
|
||||
* so UWP and RWP are RAZ/WI. And GICR_TYPER.LPIS is 0 (we don't
|
||||
* implement LPIs) so Enable_LPIs is RES0. So there are no writable
|
||||
* bits for us.
|
||||
* so UWP and RWP are RAZ/WI. GICR_TYPER.LPIS is 1 (we
|
||||
* implement LPIs) so Enable_LPIs is programmable.
|
||||
*/
|
||||
if (cs->gicr_typer & GICR_TYPER_PLPIS) {
|
||||
if (value & GICR_CTLR_ENABLE_LPIS) {
|
||||
cs->gicr_ctlr |= GICR_CTLR_ENABLE_LPIS;
|
||||
/* Check for any pending interr in pending table */
|
||||
gicv3_redist_update_lpi(cs);
|
||||
gicv3_redist_update(cs);
|
||||
} else {
|
||||
cs->gicr_ctlr &= ~GICR_CTLR_ENABLE_LPIS;
|
||||
}
|
||||
}
|
||||
return MEMTX_OK;
|
||||
case GICR_STATUSR:
|
||||
/* RAZ/WI for our implementation */
|
||||
|
@ -526,6 +535,144 @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data,
|
|||
return r;
|
||||
}
|
||||
|
||||
static void gicv3_redist_check_lpi_priority(GICv3CPUState *cs, int irq)
|
||||
{
|
||||
AddressSpace *as = &cs->gic->dma_as;
|
||||
uint64_t lpict_baddr;
|
||||
uint8_t lpite;
|
||||
uint8_t prio;
|
||||
|
||||
lpict_baddr = cs->gicr_propbaser & R_GICR_PROPBASER_PHYADDR_MASK;
|
||||
|
||||
address_space_read(as, lpict_baddr + ((irq - GICV3_LPI_INTID_START) *
|
||||
sizeof(lpite)), MEMTXATTRS_UNSPECIFIED, &lpite,
|
||||
sizeof(lpite));
|
||||
|
||||
if (!(lpite & LPI_CTE_ENABLED)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cs->gic->gicd_ctlr & GICD_CTLR_DS) {
|
||||
prio = lpite & LPI_PRIORITY_MASK;
|
||||
} else {
|
||||
prio = ((lpite & LPI_PRIORITY_MASK) >> 1) | 0x80;
|
||||
}
|
||||
|
||||
if ((prio < cs->hpplpi.prio) ||
|
||||
((prio == cs->hpplpi.prio) && (irq <= cs->hpplpi.irq))) {
|
||||
cs->hpplpi.irq = irq;
|
||||
cs->hpplpi.prio = prio;
|
||||
/* LPIs are always non-secure Grp1 interrupts */
|
||||
cs->hpplpi.grp = GICV3_G1NS;
|
||||
}
|
||||
}
|
||||
|
||||
void gicv3_redist_update_lpi(GICv3CPUState *cs)
|
||||
{
|
||||
/*
|
||||
* This function scans the LPI pending table and for each pending
|
||||
* LPI, reads the corresponding entry from LPI configuration table
|
||||
* to extract the priority info and determine if the current LPI
|
||||
* priority is lower than the last computed high priority lpi interrupt.
|
||||
* If yes, replace current LPI as the new high priority lpi interrupt.
|
||||
*/
|
||||
AddressSpace *as = &cs->gic->dma_as;
|
||||
uint64_t lpipt_baddr;
|
||||
uint32_t pendt_size = 0;
|
||||
uint8_t pend;
|
||||
int i, bit;
|
||||
uint64_t idbits;
|
||||
|
||||
idbits = MIN(FIELD_EX64(cs->gicr_propbaser, GICR_PROPBASER, IDBITS),
|
||||
GICD_TYPER_IDBITS);
|
||||
|
||||
if (!(cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) || !cs->gicr_propbaser ||
|
||||
!cs->gicr_pendbaser) {
|
||||
return;
|
||||
}
|
||||
|
||||
cs->hpplpi.prio = 0xff;
|
||||
|
||||
lpipt_baddr = cs->gicr_pendbaser & R_GICR_PENDBASER_PHYADDR_MASK;
|
||||
|
||||
/* Determine the highest priority pending interrupt among LPIs */
|
||||
pendt_size = (1ULL << (idbits + 1));
|
||||
|
||||
for (i = GICV3_LPI_INTID_START / 8; i < pendt_size / 8; i++) {
|
||||
address_space_read(as, lpipt_baddr + i, MEMTXATTRS_UNSPECIFIED, &pend,
|
||||
sizeof(pend));
|
||||
|
||||
while (pend) {
|
||||
bit = ctz32(pend);
|
||||
gicv3_redist_check_lpi_priority(cs, i * 8 + bit);
|
||||
pend &= ~(1 << bit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gicv3_redist_lpi_pending(GICv3CPUState *cs, int irq, int level)
|
||||
{
|
||||
/*
|
||||
* This function updates the pending bit in lpi pending table for
|
||||
* the irq being activated or deactivated.
|
||||
*/
|
||||
AddressSpace *as = &cs->gic->dma_as;
|
||||
uint64_t lpipt_baddr;
|
||||
bool ispend = false;
|
||||
uint8_t pend;
|
||||
|
||||
/*
|
||||
* get the bit value corresponding to this irq in the
|
||||
* lpi pending table
|
||||
*/
|
||||
lpipt_baddr = cs->gicr_pendbaser & R_GICR_PENDBASER_PHYADDR_MASK;
|
||||
|
||||
address_space_read(as, lpipt_baddr + ((irq / 8) * sizeof(pend)),
|
||||
MEMTXATTRS_UNSPECIFIED, &pend, sizeof(pend));
|
||||
|
||||
ispend = extract32(pend, irq % 8, 1);
|
||||
|
||||
/* no change in the value of pending bit, return */
|
||||
if (ispend == level) {
|
||||
return;
|
||||
}
|
||||
pend = deposit32(pend, irq % 8, 1, level ? 1 : 0);
|
||||
|
||||
address_space_write(as, lpipt_baddr + ((irq / 8) * sizeof(pend)),
|
||||
MEMTXATTRS_UNSPECIFIED, &pend, sizeof(pend));
|
||||
|
||||
/*
|
||||
* check if this LPI is better than the current hpplpi, if yes
|
||||
* just set hpplpi.prio and .irq without doing a full rescan
|
||||
*/
|
||||
if (level) {
|
||||
gicv3_redist_check_lpi_priority(cs, irq);
|
||||
} else {
|
||||
if (irq == cs->hpplpi.irq) {
|
||||
gicv3_redist_update_lpi(cs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gicv3_redist_process_lpi(GICv3CPUState *cs, int irq, int level)
|
||||
{
|
||||
uint64_t idbits;
|
||||
|
||||
idbits = MIN(FIELD_EX64(cs->gicr_propbaser, GICR_PROPBASER, IDBITS),
|
||||
GICD_TYPER_IDBITS);
|
||||
|
||||
if (!(cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) || !cs->gicr_propbaser ||
|
||||
!cs->gicr_pendbaser || (irq > (1ULL << (idbits + 1)) - 1) ||
|
||||
irq < GICV3_LPI_INTID_START) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* set/clear the pending bit for this irq */
|
||||
gicv3_redist_lpi_pending(cs, irq, level);
|
||||
|
||||
gicv3_redist_update(cs);
|
||||
}
|
||||
|
||||
void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level)
|
||||
{
|
||||
/* Update redistributor state for a change in an external PPI input line */
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#ifndef QEMU_ARM_GICV3_INTERNAL_H
|
||||
#define QEMU_ARM_GICV3_INTERNAL_H
|
||||
|
||||
#include "hw/registerfields.h"
|
||||
#include "hw/intc/arm_gicv3_common.h"
|
||||
|
||||
/* Distributor registers, as offsets from the distributor base address */
|
||||
|
@ -67,6 +68,11 @@
|
|||
#define GICD_CTLR_E1NWF (1U << 7)
|
||||
#define GICD_CTLR_RWP (1U << 31)
|
||||
|
||||
#define GICD_TYPER_LPIS_SHIFT 17
|
||||
|
||||
/* 16 bits EventId */
|
||||
#define GICD_TYPER_IDBITS 0xf
|
||||
|
||||
/*
|
||||
* Redistributor frame offsets from RD_base
|
||||
*/
|
||||
|
@ -122,17 +128,19 @@
|
|||
#define GICR_WAKER_ProcessorSleep (1U << 1)
|
||||
#define GICR_WAKER_ChildrenAsleep (1U << 2)
|
||||
|
||||
#define GICR_PROPBASER_OUTER_CACHEABILITY_MASK (7ULL << 56)
|
||||
#define GICR_PROPBASER_ADDR_MASK (0xfffffffffULL << 12)
|
||||
#define GICR_PROPBASER_SHAREABILITY_MASK (3U << 10)
|
||||
#define GICR_PROPBASER_CACHEABILITY_MASK (7U << 7)
|
||||
#define GICR_PROPBASER_IDBITS_MASK (0x1f)
|
||||
FIELD(GICR_PROPBASER, IDBITS, 0, 5)
|
||||
FIELD(GICR_PROPBASER, INNERCACHE, 7, 3)
|
||||
FIELD(GICR_PROPBASER, SHAREABILITY, 10, 2)
|
||||
FIELD(GICR_PROPBASER, PHYADDR, 12, 40)
|
||||
FIELD(GICR_PROPBASER, OUTERCACHE, 56, 3)
|
||||
|
||||
#define GICR_PENDBASER_PTZ (1ULL << 62)
|
||||
#define GICR_PENDBASER_OUTER_CACHEABILITY_MASK (7ULL << 56)
|
||||
#define GICR_PENDBASER_ADDR_MASK (0xffffffffULL << 16)
|
||||
#define GICR_PENDBASER_SHAREABILITY_MASK (3U << 10)
|
||||
#define GICR_PENDBASER_CACHEABILITY_MASK (7U << 7)
|
||||
FIELD(GICR_PENDBASER, INNERCACHE, 7, 3)
|
||||
FIELD(GICR_PENDBASER, SHAREABILITY, 10, 2)
|
||||
FIELD(GICR_PENDBASER, PHYADDR, 16, 36)
|
||||
FIELD(GICR_PENDBASER, OUTERCACHE, 56, 3)
|
||||
FIELD(GICR_PENDBASER, PTZ, 62, 1)
|
||||
|
||||
#define GICR_PROPBASER_IDBITS_THRESHOLD 0xd
|
||||
|
||||
#define ICC_CTLR_EL1_CBPR (1U << 0)
|
||||
#define ICC_CTLR_EL1_EOIMODE (1U << 1)
|
||||
|
@ -239,6 +247,163 @@
|
|||
#define ICH_VTR_EL2_PREBITS_SHIFT 26
|
||||
#define ICH_VTR_EL2_PRIBITS_SHIFT 29
|
||||
|
||||
/* ITS Registers */
|
||||
|
||||
FIELD(GITS_BASER, SIZE, 0, 8)
|
||||
FIELD(GITS_BASER, PAGESIZE, 8, 2)
|
||||
FIELD(GITS_BASER, SHAREABILITY, 10, 2)
|
||||
FIELD(GITS_BASER, PHYADDR, 12, 36)
|
||||
FIELD(GITS_BASER, PHYADDRL_64K, 16, 32)
|
||||
FIELD(GITS_BASER, PHYADDRH_64K, 12, 4)
|
||||
FIELD(GITS_BASER, ENTRYSIZE, 48, 5)
|
||||
FIELD(GITS_BASER, OUTERCACHE, 53, 3)
|
||||
FIELD(GITS_BASER, TYPE, 56, 3)
|
||||
FIELD(GITS_BASER, INNERCACHE, 59, 3)
|
||||
FIELD(GITS_BASER, INDIRECT, 62, 1)
|
||||
FIELD(GITS_BASER, VALID, 63, 1)
|
||||
|
||||
FIELD(GITS_CBASER, SIZE, 0, 8)
|
||||
FIELD(GITS_CBASER, SHAREABILITY, 10, 2)
|
||||
FIELD(GITS_CBASER, PHYADDR, 12, 40)
|
||||
FIELD(GITS_CBASER, OUTERCACHE, 53, 3)
|
||||
FIELD(GITS_CBASER, INNERCACHE, 59, 3)
|
||||
FIELD(GITS_CBASER, VALID, 63, 1)
|
||||
|
||||
FIELD(GITS_CREADR, STALLED, 0, 1)
|
||||
FIELD(GITS_CREADR, OFFSET, 5, 15)
|
||||
|
||||
FIELD(GITS_CWRITER, RETRY, 0, 1)
|
||||
FIELD(GITS_CWRITER, OFFSET, 5, 15)
|
||||
|
||||
FIELD(GITS_CTLR, ENABLED, 0, 1)
|
||||
FIELD(GITS_CTLR, QUIESCENT, 31, 1)
|
||||
|
||||
FIELD(GITS_TYPER, PHYSICAL, 0, 1)
|
||||
FIELD(GITS_TYPER, ITT_ENTRY_SIZE, 4, 4)
|
||||
FIELD(GITS_TYPER, IDBITS, 8, 5)
|
||||
FIELD(GITS_TYPER, DEVBITS, 13, 5)
|
||||
FIELD(GITS_TYPER, SEIS, 18, 1)
|
||||
FIELD(GITS_TYPER, PTA, 19, 1)
|
||||
FIELD(GITS_TYPER, CIDBITS, 32, 4)
|
||||
FIELD(GITS_TYPER, CIL, 36, 1)
|
||||
|
||||
#define GITS_IDREGS 0xFFD0
|
||||
|
||||
#define ITS_CTLR_ENABLED (1U) /* ITS Enabled */
|
||||
|
||||
#define GITS_BASER_RO_MASK (R_GITS_BASER_ENTRYSIZE_MASK | \
|
||||
R_GITS_BASER_TYPE_MASK)
|
||||
|
||||
#define GITS_BASER_PAGESIZE_4K 0
|
||||
#define GITS_BASER_PAGESIZE_16K 1
|
||||
#define GITS_BASER_PAGESIZE_64K 2
|
||||
|
||||
#define GITS_BASER_TYPE_DEVICE 1ULL
|
||||
#define GITS_BASER_TYPE_COLLECTION 4ULL
|
||||
|
||||
#define GITS_PAGE_SIZE_4K 0x1000
|
||||
#define GITS_PAGE_SIZE_16K 0x4000
|
||||
#define GITS_PAGE_SIZE_64K 0x10000
|
||||
|
||||
#define L1TABLE_ENTRY_SIZE 8
|
||||
|
||||
#define LPI_CTE_ENABLED TABLE_ENTRY_VALID_MASK
|
||||
#define LPI_PRIORITY_MASK 0xfc
|
||||
|
||||
#define GITS_CMDQ_ENTRY_SIZE 32
|
||||
#define NUM_BYTES_IN_DW 8
|
||||
|
||||
#define CMD_MASK 0xff
|
||||
|
||||
/* ITS Commands */
|
||||
#define GITS_CMD_CLEAR 0x04
|
||||
#define GITS_CMD_DISCARD 0x0F
|
||||
#define GITS_CMD_INT 0x03
|
||||
#define GITS_CMD_MAPC 0x09
|
||||
#define GITS_CMD_MAPD 0x08
|
||||
#define GITS_CMD_MAPI 0x0B
|
||||
#define GITS_CMD_MAPTI 0x0A
|
||||
#define GITS_CMD_INV 0x0C
|
||||
#define GITS_CMD_INVALL 0x0D
|
||||
#define GITS_CMD_SYNC 0x05
|
||||
|
||||
/* MAPC command fields */
|
||||
#define ICID_LENGTH 16
|
||||
#define ICID_MASK ((1U << ICID_LENGTH) - 1)
|
||||
FIELD(MAPC, RDBASE, 16, 32)
|
||||
|
||||
#define RDBASE_PROCNUM_LENGTH 16
|
||||
#define RDBASE_PROCNUM_MASK ((1ULL << RDBASE_PROCNUM_LENGTH) - 1)
|
||||
|
||||
/* MAPD command fields */
|
||||
#define ITTADDR_LENGTH 44
|
||||
#define ITTADDR_SHIFT 8
|
||||
#define ITTADDR_MASK MAKE_64BIT_MASK(ITTADDR_SHIFT, ITTADDR_LENGTH)
|
||||
#define SIZE_MASK 0x1f
|
||||
|
||||
/* MAPI command fields */
|
||||
#define EVENTID_MASK ((1ULL << 32) - 1)
|
||||
|
||||
/* MAPTI command fields */
|
||||
#define pINTID_SHIFT 32
|
||||
#define pINTID_MASK MAKE_64BIT_MASK(32, 32)
|
||||
|
||||
#define DEVID_SHIFT 32
|
||||
#define DEVID_MASK MAKE_64BIT_MASK(32, 32)
|
||||
|
||||
#define VALID_SHIFT 63
|
||||
#define CMD_FIELD_VALID_MASK (1ULL << VALID_SHIFT)
|
||||
#define L2_TABLE_VALID_MASK CMD_FIELD_VALID_MASK
|
||||
#define TABLE_ENTRY_VALID_MASK (1ULL << 0)
|
||||
|
||||
/**
|
||||
* Default features advertised by this version of ITS
|
||||
*/
|
||||
/* Physical LPIs supported */
|
||||
#define GITS_TYPE_PHYSICAL (1U << 0)
|
||||
|
||||
/*
|
||||
* 12 bytes Interrupt translation Table Entry size
|
||||
* as per Table 5.3 in GICv3 spec
|
||||
* ITE Lower 8 Bytes
|
||||
* Bits: | 49 ... 26 | 25 ... 2 | 1 | 0 |
|
||||
* Values: | 1023 | IntNum | IntType | Valid |
|
||||
* ITE Higher 4 Bytes
|
||||
* Bits: | 31 ... 16 | 15 ...0 |
|
||||
* Values: | vPEID | ICID |
|
||||
*/
|
||||
#define ITS_ITT_ENTRY_SIZE 0xC
|
||||
#define ITE_ENTRY_INTTYPE_SHIFT 1
|
||||
#define ITE_ENTRY_INTID_SHIFT 2
|
||||
#define ITE_ENTRY_INTID_MASK MAKE_64BIT_MASK(2, 24)
|
||||
#define ITE_ENTRY_INTSP_SHIFT 26
|
||||
#define ITE_ENTRY_ICID_MASK MAKE_64BIT_MASK(0, 16)
|
||||
|
||||
/* 16 bits EventId */
|
||||
#define ITS_IDBITS GICD_TYPER_IDBITS
|
||||
|
||||
/* 16 bits DeviceId */
|
||||
#define ITS_DEVBITS 0xF
|
||||
|
||||
/* 16 bits CollectionId */
|
||||
#define ITS_CIDBITS 0xF
|
||||
|
||||
/*
|
||||
* 8 bytes Device Table Entry size
|
||||
* Valid = 1 bit,ITTAddr = 44 bits,Size = 5 bits
|
||||
*/
|
||||
#define GITS_DTE_SIZE (0x8ULL)
|
||||
#define GITS_DTE_ITTADDR_SHIFT 6
|
||||
#define GITS_DTE_ITTADDR_MASK MAKE_64BIT_MASK(GITS_DTE_ITTADDR_SHIFT, \
|
||||
ITTADDR_LENGTH)
|
||||
|
||||
/*
|
||||
* 8 bytes Collection Table Entry size
|
||||
* Valid = 1 bit,RDBase = 36 bits(considering max RDBASE)
|
||||
*/
|
||||
#define GITS_CTE_SIZE (0x8ULL)
|
||||
#define GITS_CTE_RDBASE_PROCNUM_MASK MAKE_64BIT_MASK(1, RDBASE_PROCNUM_LENGTH)
|
||||
|
||||
/* Special interrupt IDs */
|
||||
#define INTID_SECURE 1020
|
||||
#define INTID_NONSECURE 1021
|
||||
|
@ -296,6 +461,9 @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data,
|
|||
unsigned size, MemTxAttrs attrs);
|
||||
void gicv3_dist_set_irq(GICv3State *s, int irq, int level);
|
||||
void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level);
|
||||
void gicv3_redist_process_lpi(GICv3CPUState *cs, int irq, int level);
|
||||
void gicv3_redist_lpi_pending(GICv3CPUState *cs, int irq, int level);
|
||||
void gicv3_redist_update_lpi(GICv3CPUState *cs);
|
||||
void gicv3_redist_send_sgi(GICv3CPUState *cs, int grp, int irq, bool ns);
|
||||
void gicv3_init_cpuif(GICv3State *s);
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ softmmu_ss.add(when: 'CONFIG_ARM_GIC', if_true: files(
|
|||
'arm_gicv3_dist.c',
|
||||
'arm_gicv3_its_common.c',
|
||||
'arm_gicv3_redist.c',
|
||||
'arm_gicv3_its.c',
|
||||
))
|
||||
softmmu_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_pic.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_HEATHROW_PIC', if_true: files('heathrow_pic.c'))
|
||||
|
|
|
@ -269,6 +269,21 @@ static uint64_t zynq_slcr_compute_clock(const uint64_t periods[],
|
|||
zynq_slcr_compute_clock((plls), (state)->regs[reg], \
|
||||
reg ## _ ## enable_field ## _SHIFT)
|
||||
|
||||
static void zynq_slcr_compute_clocks_internal(ZynqSLCRState *s, uint64_t ps_clk)
|
||||
{
|
||||
uint64_t io_pll = zynq_slcr_compute_pll(ps_clk, s->regs[R_IO_PLL_CTRL]);
|
||||
uint64_t arm_pll = zynq_slcr_compute_pll(ps_clk, s->regs[R_ARM_PLL_CTRL]);
|
||||
uint64_t ddr_pll = zynq_slcr_compute_pll(ps_clk, s->regs[R_DDR_PLL_CTRL]);
|
||||
|
||||
uint64_t uart_mux[4] = {io_pll, io_pll, arm_pll, ddr_pll};
|
||||
|
||||
/* compute uartX reference clocks */
|
||||
clock_set(s->uart0_ref_clk,
|
||||
ZYNQ_COMPUTE_CLK(s, uart_mux, R_UART_CLK_CTRL, CLKACT0));
|
||||
clock_set(s->uart1_ref_clk,
|
||||
ZYNQ_COMPUTE_CLK(s, uart_mux, R_UART_CLK_CTRL, CLKACT1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute and set the ouputs clocks periods.
|
||||
* But do not propagate them further. Connected clocks
|
||||
|
@ -283,17 +298,7 @@ static void zynq_slcr_compute_clocks(ZynqSLCRState *s)
|
|||
ps_clk = 0;
|
||||
}
|
||||
|
||||
uint64_t io_pll = zynq_slcr_compute_pll(ps_clk, s->regs[R_IO_PLL_CTRL]);
|
||||
uint64_t arm_pll = zynq_slcr_compute_pll(ps_clk, s->regs[R_ARM_PLL_CTRL]);
|
||||
uint64_t ddr_pll = zynq_slcr_compute_pll(ps_clk, s->regs[R_DDR_PLL_CTRL]);
|
||||
|
||||
uint64_t uart_mux[4] = {io_pll, io_pll, arm_pll, ddr_pll};
|
||||
|
||||
/* compute uartX reference clocks */
|
||||
clock_set(s->uart0_ref_clk,
|
||||
ZYNQ_COMPUTE_CLK(s, uart_mux, R_UART_CLK_CTRL, CLKACT0));
|
||||
clock_set(s->uart1_ref_clk,
|
||||
ZYNQ_COMPUTE_CLK(s, uart_mux, R_UART_CLK_CTRL, CLKACT1));
|
||||
zynq_slcr_compute_clocks_internal(s, ps_clk);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -416,7 +421,7 @@ static void zynq_slcr_reset_hold(Object *obj)
|
|||
ZynqSLCRState *s = ZYNQ_SLCR(obj);
|
||||
|
||||
/* will disable all output clocks */
|
||||
zynq_slcr_compute_clocks(s);
|
||||
zynq_slcr_compute_clocks_internal(s, 0);
|
||||
zynq_slcr_propagate_clocks(s);
|
||||
}
|
||||
|
||||
|
@ -425,7 +430,7 @@ static void zynq_slcr_reset_exit(Object *obj)
|
|||
ZynqSLCRState *s = ZYNQ_SLCR(obj);
|
||||
|
||||
/* will compute output clocks according to ps_clk and registers */
|
||||
zynq_slcr_compute_clocks(s);
|
||||
zynq_slcr_compute_clocks_internal(s, clock_get(s->ps_clk));
|
||||
zynq_slcr_propagate_clocks(s);
|
||||
}
|
||||
|
||||
|
|
|
@ -120,6 +120,7 @@ struct VirtMachineClass {
|
|||
MachineClass parent;
|
||||
bool disallow_affinity_adjustment;
|
||||
bool no_its;
|
||||
bool no_tcg_its;
|
||||
bool no_pmu;
|
||||
bool claim_edge_triggered_timers;
|
||||
bool smbios_old_sys_ver;
|
||||
|
@ -141,6 +142,7 @@ struct VirtMachineState {
|
|||
bool highmem;
|
||||
bool highmem_ecam;
|
||||
bool its;
|
||||
bool tcg_its;
|
||||
bool virt;
|
||||
bool ras;
|
||||
bool mte;
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
#define GICV3_MAXIRQ 1020
|
||||
#define GICV3_MAXSPI (GICV3_MAXIRQ - GIC_INTERNAL)
|
||||
|
||||
#define GICV3_LPI_INTID_START 8192
|
||||
|
||||
#define GICV3_REDIST_SIZE 0x20000
|
||||
|
||||
/* Number of SGI target-list bits */
|
||||
|
@ -202,6 +204,13 @@ struct GICv3CPUState {
|
|||
* real state above; it doesn't need to be migrated.
|
||||
*/
|
||||
PendingIrq hppi;
|
||||
|
||||
/*
|
||||
* Cached information recalculated from LPI tables
|
||||
* in guest memory
|
||||
*/
|
||||
PendingIrq hpplpi;
|
||||
|
||||
/* This is temporary working state, to avoid a malloc in gicv3_update() */
|
||||
bool seenbetter;
|
||||
};
|
||||
|
@ -219,6 +228,7 @@ struct GICv3State {
|
|||
uint32_t num_cpu;
|
||||
uint32_t num_irq;
|
||||
uint32_t revision;
|
||||
bool lpi_enable;
|
||||
bool security_extn;
|
||||
bool irq_reset_nonsecure;
|
||||
bool gicd_no_migration_shift_bug;
|
||||
|
@ -226,6 +236,9 @@ struct GICv3State {
|
|||
int dev_fd; /* kvm device fd if backed by kvm vgic support */
|
||||
Error *migration_blocker;
|
||||
|
||||
MemoryRegion *dma;
|
||||
AddressSpace dma_as;
|
||||
|
||||
/* Distributor */
|
||||
|
||||
/* for a GIC with the security extensions the NS banked version of this
|
||||
|
|
|
@ -25,17 +25,41 @@
|
|||
#include "hw/intc/arm_gicv3_common.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define TYPE_ARM_GICV3_ITS "arm-gicv3-its"
|
||||
|
||||
#define ITS_CONTROL_SIZE 0x10000
|
||||
#define ITS_TRANS_SIZE 0x10000
|
||||
#define ITS_SIZE (ITS_CONTROL_SIZE + ITS_TRANS_SIZE)
|
||||
|
||||
#define GITS_CTLR 0x0
|
||||
#define GITS_IIDR 0x4
|
||||
#define GITS_TYPER 0x8
|
||||
#define GITS_CBASER 0x80
|
||||
#define GITS_CWRITER 0x88
|
||||
#define GITS_CREADR 0x90
|
||||
#define GITS_BASER 0x100
|
||||
|
||||
#define GITS_TRANSLATER 0x0040
|
||||
|
||||
typedef struct {
|
||||
bool valid;
|
||||
bool indirect;
|
||||
uint16_t entry_sz;
|
||||
uint32_t page_sz;
|
||||
uint32_t max_entries;
|
||||
union {
|
||||
uint32_t max_devids;
|
||||
uint32_t max_collids;
|
||||
} maxids;
|
||||
uint64_t base_addr;
|
||||
} TableDesc;
|
||||
|
||||
typedef struct {
|
||||
bool valid;
|
||||
uint32_t max_entries;
|
||||
uint64_t base_addr;
|
||||
} CmdQDesc;
|
||||
|
||||
struct GICv3ITSState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
|
@ -52,17 +76,23 @@ struct GICv3ITSState {
|
|||
/* Registers */
|
||||
uint32_t ctlr;
|
||||
uint32_t iidr;
|
||||
uint64_t typer;
|
||||
uint64_t cbaser;
|
||||
uint64_t cwriter;
|
||||
uint64_t creadr;
|
||||
uint64_t baser[8];
|
||||
|
||||
TableDesc dt;
|
||||
TableDesc ct;
|
||||
CmdQDesc cq;
|
||||
|
||||
Error *migration_blocker;
|
||||
};
|
||||
|
||||
typedef struct GICv3ITSState GICv3ITSState;
|
||||
|
||||
void gicv3_its_init_mmio(GICv3ITSState *s, const MemoryRegionOps *ops);
|
||||
void gicv3_its_init_mmio(GICv3ITSState *s, const MemoryRegionOps *ops,
|
||||
const MemoryRegionOps *tops);
|
||||
|
||||
#define TYPE_ARM_GICV3_ITS_COMMON "arm-gicv3-its-common"
|
||||
typedef struct GICv3ITSCommonClass GICv3ITSCommonClass;
|
||||
|
|
|
@ -264,6 +264,7 @@ struct BusState {
|
|||
HotplugHandler *hotplug_handler;
|
||||
int max_index;
|
||||
bool realized;
|
||||
bool full;
|
||||
int num_children;
|
||||
|
||||
/*
|
||||
|
@ -798,6 +799,29 @@ static inline bool qbus_is_hotpluggable(BusState *bus)
|
|||
return bus->hotplug_handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* qbus_mark_full: Mark this bus as full, so no more devices can be attached
|
||||
* @bus: Bus to mark as full
|
||||
*
|
||||
* By default, QEMU will allow devices to be plugged into a bus up
|
||||
* to the bus class's device count limit. Calling this function
|
||||
* marks a particular bus as full, so that no more devices can be
|
||||
* plugged into it. In particular this means that the bus will not
|
||||
* be considered as a candidate for plugging in devices created by
|
||||
* the user on the commandline or via the monitor.
|
||||
* If a machine has multiple buses of a given type, such as I2C,
|
||||
* where some of those buses in the real hardware are used only for
|
||||
* internal devices and some are exposed via expansion ports, you
|
||||
* can use this function to mark the internal-only buses as full
|
||||
* after you have created all their internal devices. Then user
|
||||
* created devices will appear on the expansion-port bus where
|
||||
* guest software expects them.
|
||||
*/
|
||||
static inline void qbus_mark_full(BusState *bus)
|
||||
{
|
||||
bus->full = true;
|
||||
}
|
||||
|
||||
void device_listener_register(DeviceListener *listener);
|
||||
void device_listener_unregister(DeviceListener *listener);
|
||||
|
||||
|
|
|
@ -435,7 +435,12 @@ static DeviceState *qbus_find_dev(BusState *bus, char *elem)
|
|||
|
||||
static inline bool qbus_is_full(BusState *bus)
|
||||
{
|
||||
BusClass *bus_class = BUS_GET_CLASS(bus);
|
||||
BusClass *bus_class;
|
||||
|
||||
if (bus->full) {
|
||||
return true;
|
||||
}
|
||||
bus_class = BUS_GET_CLASS(bus);
|
||||
return bus_class->max_dev && bus->num_children >= bus_class->max_dev;
|
||||
}
|
||||
|
||||
|
|
|
@ -3455,6 +3455,7 @@ FIELD(TBFLAG_ANY, FPEXC_EL, 8, 2)
|
|||
FIELD(TBFLAG_ANY, DEBUG_TARGET_EL, 10, 2)
|
||||
/* Memory operations require alignment: SCTLR_ELx.A or CCR.UNALIGN_TRP */
|
||||
FIELD(TBFLAG_ANY, ALIGN_MEM, 12, 1)
|
||||
FIELD(TBFLAG_ANY, PSTATE__IL, 13, 1)
|
||||
|
||||
/*
|
||||
* Bit usage when in AArch32 state, both A- and M-profile.
|
||||
|
|
|
@ -1071,6 +1071,7 @@ illegal_return:
|
|||
if (!arm_singlestep_active(env)) {
|
||||
env->pstate &= ~PSTATE_SS;
|
||||
}
|
||||
helper_rebuild_hflags_a64(env, cur_el);
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "Illegal exception return at EL%d: "
|
||||
"resuming execution at 0x%" PRIx64 "\n", cur_el, env->pc);
|
||||
}
|
||||
|
|
|
@ -13462,6 +13462,10 @@ static CPUARMTBFlags rebuild_hflags_a32(CPUARMState *env, int fp_el,
|
|||
DP_TBFLAG_A32(flags, HSTR_ACTIVE, 1);
|
||||
}
|
||||
|
||||
if (env->uncached_cpsr & CPSR_IL) {
|
||||
DP_TBFLAG_ANY(flags, PSTATE__IL, 1);
|
||||
}
|
||||
|
||||
return rebuild_hflags_common_32(env, fp_el, mmu_idx, flags);
|
||||
}
|
||||
|
||||
|
@ -13556,6 +13560,10 @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el,
|
|||
}
|
||||
}
|
||||
|
||||
if (env->pstate & PSTATE_IL) {
|
||||
DP_TBFLAG_ANY(flags, PSTATE__IL, 1);
|
||||
}
|
||||
|
||||
if (cpu_isar_feature(aa64_mte, env_archcpu(env))) {
|
||||
/*
|
||||
* Set MTE_ACTIVE if any access may be Checked, and leave clear
|
||||
|
|
|
@ -70,12 +70,17 @@ bool kvm_arm_create_scratch_host_vcpu(const uint32_t *cpus_to_try,
|
|||
struct kvm_vcpu_init *init)
|
||||
{
|
||||
int ret = 0, kvmfd = -1, vmfd = -1, cpufd = -1;
|
||||
int max_vm_pa_size;
|
||||
|
||||
kvmfd = qemu_open_old("/dev/kvm", O_RDWR);
|
||||
if (kvmfd < 0) {
|
||||
goto err;
|
||||
}
|
||||
vmfd = ioctl(kvmfd, KVM_CREATE_VM, 0);
|
||||
max_vm_pa_size = ioctl(kvmfd, KVM_CHECK_EXTENSION, KVM_CAP_ARM_VM_IPA_SIZE);
|
||||
if (max_vm_pa_size < 0) {
|
||||
max_vm_pa_size = 0;
|
||||
}
|
||||
vmfd = ioctl(kvmfd, KVM_CREATE_VM, max_vm_pa_size);
|
||||
if (vmfd < 0) {
|
||||
goto err;
|
||||
}
|
||||
|
|
|
@ -525,8 +525,8 @@ static inline const char *its_class_name(void)
|
|||
/* KVM implementation requires this capability */
|
||||
return kvm_direct_msi_enabled() ? "arm-its-kvm" : NULL;
|
||||
} else {
|
||||
/* Software emulation is not implemented yet */
|
||||
return NULL;
|
||||
/* Software emulation based model */
|
||||
return "arm-gicv3-its";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -277,4 +277,9 @@ static inline uint32_t syn_wfx(int cv, int cond, int ti, bool is_16bit)
|
|||
(cv << 24) | (cond << 20) | ti;
|
||||
}
|
||||
|
||||
static inline uint32_t syn_illegalstate(void)
|
||||
{
|
||||
return (EC_ILLEGALSTATE << ARM_EL_EC_SHIFT) | ARM_EL_IL;
|
||||
}
|
||||
|
||||
#endif /* TARGET_ARM_SYNDROME_H */
|
||||
|
|
|
@ -14649,11 +14649,128 @@ static bool btype_destination_ok(uint32_t insn, bool bt, int btype)
|
|||
return false;
|
||||
}
|
||||
|
||||
/* C3.1 A64 instruction index by encoding */
|
||||
static void disas_a64_insn(CPUARMState *env, DisasContext *s)
|
||||
static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
|
||||
CPUState *cpu)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
CPUARMState *env = cpu->env_ptr;
|
||||
ARMCPU *arm_cpu = env_archcpu(env);
|
||||
CPUARMTBFlags tb_flags = arm_tbflags_from_tb(dc->base.tb);
|
||||
int bound, core_mmu_idx;
|
||||
|
||||
dc->isar = &arm_cpu->isar;
|
||||
dc->condjmp = 0;
|
||||
|
||||
dc->aarch64 = 1;
|
||||
/* 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->sctlr_b = 0;
|
||||
dc->be_data = EX_TBFLAG_ANY(tb_flags, BE_DATA) ? MO_BE : MO_LE;
|
||||
dc->condexec_mask = 0;
|
||||
dc->condexec_cond = 0;
|
||||
core_mmu_idx = EX_TBFLAG_ANY(tb_flags, MMUIDX);
|
||||
dc->mmu_idx = core_to_aa64_mmu_idx(core_mmu_idx);
|
||||
dc->tbii = EX_TBFLAG_A64(tb_flags, TBII);
|
||||
dc->tbid = EX_TBFLAG_A64(tb_flags, TBID);
|
||||
dc->tcma = EX_TBFLAG_A64(tb_flags, TCMA);
|
||||
dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
dc->user = (dc->current_el == 0);
|
||||
#endif
|
||||
dc->fp_excp_el = EX_TBFLAG_ANY(tb_flags, FPEXC_EL);
|
||||
dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM);
|
||||
dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL);
|
||||
dc->sve_excp_el = EX_TBFLAG_A64(tb_flags, SVEEXC_EL);
|
||||
dc->sve_len = (EX_TBFLAG_A64(tb_flags, ZCR_LEN) + 1) * 16;
|
||||
dc->pauth_active = EX_TBFLAG_A64(tb_flags, PAUTH_ACTIVE);
|
||||
dc->bt = EX_TBFLAG_A64(tb_flags, BT);
|
||||
dc->btype = EX_TBFLAG_A64(tb_flags, BTYPE);
|
||||
dc->unpriv = EX_TBFLAG_A64(tb_flags, UNPRIV);
|
||||
dc->ata = EX_TBFLAG_A64(tb_flags, ATA);
|
||||
dc->mte_active[0] = EX_TBFLAG_A64(tb_flags, MTE_ACTIVE);
|
||||
dc->mte_active[1] = EX_TBFLAG_A64(tb_flags, MTE0_ACTIVE);
|
||||
dc->vec_len = 0;
|
||||
dc->vec_stride = 0;
|
||||
dc->cp_regs = arm_cpu->cp_regs;
|
||||
dc->features = env->features;
|
||||
dc->dcz_blocksize = arm_cpu->dcz_blocksize;
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
/* In sve_probe_page, we assume TBI is enabled. */
|
||||
tcg_debug_assert(dc->tbid & 1);
|
||||
#endif
|
||||
|
||||
/* Single step state. The code-generation logic here is:
|
||||
* SS_ACTIVE == 0:
|
||||
* generate code with no special handling for single-stepping (except
|
||||
* that anything that can make us go to SS_ACTIVE == 1 must end the TB;
|
||||
* this happens anyway because those changes are all system register or
|
||||
* PSTATE writes).
|
||||
* SS_ACTIVE == 1, PSTATE.SS == 1: (active-not-pending)
|
||||
* emit code for one insn
|
||||
* emit code to clear PSTATE.SS
|
||||
* emit code to generate software step exception for completed step
|
||||
* end TB (as usual for having generated an exception)
|
||||
* SS_ACTIVE == 1, PSTATE.SS == 0: (active-pending)
|
||||
* emit code to generate a software step exception
|
||||
* end the TB
|
||||
*/
|
||||
dc->ss_active = EX_TBFLAG_ANY(tb_flags, SS_ACTIVE);
|
||||
dc->pstate_ss = EX_TBFLAG_ANY(tb_flags, PSTATE__SS);
|
||||
dc->is_ldex = false;
|
||||
dc->debug_target_el = EX_TBFLAG_ANY(tb_flags, DEBUG_TARGET_EL);
|
||||
|
||||
/* Bound the number of insns to execute to those left on the page. */
|
||||
bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
|
||||
|
||||
/* If architectural single step active, limit to 1. */
|
||||
if (dc->ss_active) {
|
||||
bound = 1;
|
||||
}
|
||||
dc->base.max_insns = MIN(dc->base.max_insns, bound);
|
||||
|
||||
init_tmp_a64_array(dc);
|
||||
}
|
||||
|
||||
static void aarch64_tr_tb_start(DisasContextBase *db, CPUState *cpu)
|
||||
{
|
||||
}
|
||||
|
||||
static void aarch64_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
|
||||
tcg_gen_insn_start(dc->base.pc_next, 0, 0);
|
||||
dc->insn_start = tcg_last_op();
|
||||
}
|
||||
|
||||
static void aarch64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
|
||||
{
|
||||
DisasContext *s = container_of(dcbase, DisasContext, base);
|
||||
CPUARMState *env = cpu->env_ptr;
|
||||
uint32_t insn;
|
||||
|
||||
if (s->ss_active && !s->pstate_ss) {
|
||||
/* Singlestep state is Active-pending.
|
||||
* If we're in this state at the start of a TB then either
|
||||
* a) we just took an exception to an EL which is being debugged
|
||||
* and this is the first insn in the exception handler
|
||||
* b) debug exceptions were masked and we just unmasked them
|
||||
* without changing EL (eg by clearing PSTATE.D)
|
||||
* In either case we're going to take a swstep exception in the
|
||||
* "did not step an insn" case, and so the syndrome ISV and EX
|
||||
* bits should be zero.
|
||||
*/
|
||||
assert(s->base.num_insns == 1);
|
||||
gen_swstep_exception(s, 0, 0);
|
||||
s->base.is_jmp = DISAS_NORETURN;
|
||||
return;
|
||||
}
|
||||
|
||||
s->pc_curr = s->base.pc_next;
|
||||
insn = arm_ldl_code(env, s->base.pc_next, s->sctlr_b);
|
||||
s->insn = insn;
|
||||
|
@ -14662,6 +14779,16 @@ static void disas_a64_insn(CPUARMState *env, DisasContext *s)
|
|||
s->fp_access_checked = false;
|
||||
s->sve_access_checked = false;
|
||||
|
||||
if (s->pstate_il) {
|
||||
/*
|
||||
* Illegal execution state. This has priority over BTI
|
||||
* exceptions, but comes after instruction abort exceptions.
|
||||
*/
|
||||
gen_exception_insn(s, s->pc_curr, EXCP_UDEF,
|
||||
syn_illegalstate(), default_exception_el(s));
|
||||
return;
|
||||
}
|
||||
|
||||
if (dc_isar_feature(aa64_bti, s)) {
|
||||
if (s->base.num_insns == 1) {
|
||||
/*
|
||||
|
@ -14744,130 +14871,8 @@ static void disas_a64_insn(CPUARMState *env, DisasContext *s)
|
|||
if (s->btype > 0 && s->base.is_jmp != DISAS_NORETURN) {
|
||||
reset_btype(s);
|
||||
}
|
||||
}
|
||||
|
||||
static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
|
||||
CPUState *cpu)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
CPUARMState *env = cpu->env_ptr;
|
||||
ARMCPU *arm_cpu = env_archcpu(env);
|
||||
CPUARMTBFlags tb_flags = arm_tbflags_from_tb(dc->base.tb);
|
||||
int bound, core_mmu_idx;
|
||||
|
||||
dc->isar = &arm_cpu->isar;
|
||||
dc->condjmp = 0;
|
||||
|
||||
dc->aarch64 = 1;
|
||||
/* 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->sctlr_b = 0;
|
||||
dc->be_data = EX_TBFLAG_ANY(tb_flags, BE_DATA) ? MO_BE : MO_LE;
|
||||
dc->condexec_mask = 0;
|
||||
dc->condexec_cond = 0;
|
||||
core_mmu_idx = EX_TBFLAG_ANY(tb_flags, MMUIDX);
|
||||
dc->mmu_idx = core_to_aa64_mmu_idx(core_mmu_idx);
|
||||
dc->tbii = EX_TBFLAG_A64(tb_flags, TBII);
|
||||
dc->tbid = EX_TBFLAG_A64(tb_flags, TBID);
|
||||
dc->tcma = EX_TBFLAG_A64(tb_flags, TCMA);
|
||||
dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
dc->user = (dc->current_el == 0);
|
||||
#endif
|
||||
dc->fp_excp_el = EX_TBFLAG_ANY(tb_flags, FPEXC_EL);
|
||||
dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM);
|
||||
dc->sve_excp_el = EX_TBFLAG_A64(tb_flags, SVEEXC_EL);
|
||||
dc->sve_len = (EX_TBFLAG_A64(tb_flags, ZCR_LEN) + 1) * 16;
|
||||
dc->pauth_active = EX_TBFLAG_A64(tb_flags, PAUTH_ACTIVE);
|
||||
dc->bt = EX_TBFLAG_A64(tb_flags, BT);
|
||||
dc->btype = EX_TBFLAG_A64(tb_flags, BTYPE);
|
||||
dc->unpriv = EX_TBFLAG_A64(tb_flags, UNPRIV);
|
||||
dc->ata = EX_TBFLAG_A64(tb_flags, ATA);
|
||||
dc->mte_active[0] = EX_TBFLAG_A64(tb_flags, MTE_ACTIVE);
|
||||
dc->mte_active[1] = EX_TBFLAG_A64(tb_flags, MTE0_ACTIVE);
|
||||
dc->vec_len = 0;
|
||||
dc->vec_stride = 0;
|
||||
dc->cp_regs = arm_cpu->cp_regs;
|
||||
dc->features = env->features;
|
||||
dc->dcz_blocksize = arm_cpu->dcz_blocksize;
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
/* In sve_probe_page, we assume TBI is enabled. */
|
||||
tcg_debug_assert(dc->tbid & 1);
|
||||
#endif
|
||||
|
||||
/* Single step state. The code-generation logic here is:
|
||||
* SS_ACTIVE == 0:
|
||||
* generate code with no special handling for single-stepping (except
|
||||
* that anything that can make us go to SS_ACTIVE == 1 must end the TB;
|
||||
* this happens anyway because those changes are all system register or
|
||||
* PSTATE writes).
|
||||
* SS_ACTIVE == 1, PSTATE.SS == 1: (active-not-pending)
|
||||
* emit code for one insn
|
||||
* emit code to clear PSTATE.SS
|
||||
* emit code to generate software step exception for completed step
|
||||
* end TB (as usual for having generated an exception)
|
||||
* SS_ACTIVE == 1, PSTATE.SS == 0: (active-pending)
|
||||
* emit code to generate a software step exception
|
||||
* end the TB
|
||||
*/
|
||||
dc->ss_active = EX_TBFLAG_ANY(tb_flags, SS_ACTIVE);
|
||||
dc->pstate_ss = EX_TBFLAG_ANY(tb_flags, PSTATE__SS);
|
||||
dc->is_ldex = false;
|
||||
dc->debug_target_el = EX_TBFLAG_ANY(tb_flags, DEBUG_TARGET_EL);
|
||||
|
||||
/* Bound the number of insns to execute to those left on the page. */
|
||||
bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
|
||||
|
||||
/* If architectural single step active, limit to 1. */
|
||||
if (dc->ss_active) {
|
||||
bound = 1;
|
||||
}
|
||||
dc->base.max_insns = MIN(dc->base.max_insns, bound);
|
||||
|
||||
init_tmp_a64_array(dc);
|
||||
}
|
||||
|
||||
static void aarch64_tr_tb_start(DisasContextBase *db, CPUState *cpu)
|
||||
{
|
||||
}
|
||||
|
||||
static void aarch64_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
|
||||
tcg_gen_insn_start(dc->base.pc_next, 0, 0);
|
||||
dc->insn_start = tcg_last_op();
|
||||
}
|
||||
|
||||
static void aarch64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
|
||||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
CPUARMState *env = cpu->env_ptr;
|
||||
|
||||
if (dc->ss_active && !dc->pstate_ss) {
|
||||
/* Singlestep state is Active-pending.
|
||||
* If we're in this state at the start of a TB then either
|
||||
* a) we just took an exception to an EL which is being debugged
|
||||
* and this is the first insn in the exception handler
|
||||
* b) debug exceptions were masked and we just unmasked them
|
||||
* without changing EL (eg by clearing PSTATE.D)
|
||||
* In either case we're going to take a swstep exception in the
|
||||
* "did not step an insn" case, and so the syndrome ISV and EX
|
||||
* bits should be zero.
|
||||
*/
|
||||
assert(dc->base.num_insns == 1);
|
||||
gen_swstep_exception(dc, 0, 0);
|
||||
dc->base.is_jmp = DISAS_NORETURN;
|
||||
} else {
|
||||
disas_a64_insn(env, dc);
|
||||
}
|
||||
|
||||
translator_loop_temp_check(&dc->base);
|
||||
translator_loop_temp_check(&s->base);
|
||||
}
|
||||
|
||||
static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
|
||||
|
|
|
@ -9090,6 +9090,16 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
|
|||
return;
|
||||
}
|
||||
|
||||
if (s->pstate_il) {
|
||||
/*
|
||||
* Illegal execution state. This has priority over BTI
|
||||
* exceptions, but comes after instruction abort exceptions.
|
||||
*/
|
||||
gen_exception_insn(s, s->pc_curr, EXCP_UDEF,
|
||||
syn_illegalstate(), default_exception_el(s));
|
||||
return;
|
||||
}
|
||||
|
||||
if (cond == 0xf) {
|
||||
/* In ARMv3 and v4 the NV condition is UNPREDICTABLE; we
|
||||
* choose to UNDEF. In ARMv5 and above the space is used
|
||||
|
@ -9358,6 +9368,7 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
|
|||
#endif
|
||||
dc->fp_excp_el = EX_TBFLAG_ANY(tb_flags, FPEXC_EL);
|
||||
dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM);
|
||||
dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL);
|
||||
|
||||
if (arm_feature(env, ARM_FEATURE_M)) {
|
||||
dc->vfp_enabled = 1;
|
||||
|
@ -9621,6 +9632,16 @@ static void thumb_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
|
|||
}
|
||||
dc->insn = insn;
|
||||
|
||||
if (dc->pstate_il) {
|
||||
/*
|
||||
* Illegal execution state. This has priority over BTI
|
||||
* exceptions, but comes after instruction abort exceptions.
|
||||
*/
|
||||
gen_exception_insn(dc, dc->pc_curr, EXCP_UDEF,
|
||||
syn_illegalstate(), default_exception_el(dc));
|
||||
return;
|
||||
}
|
||||
|
||||
if (dc->eci) {
|
||||
/*
|
||||
* For M-profile continuable instructions, ECI/ICI handling
|
||||
|
|
|
@ -98,6 +98,8 @@ typedef struct DisasContext {
|
|||
bool hstr_active;
|
||||
/* True if memory operations require alignment */
|
||||
bool align_mem;
|
||||
/* True if PSTATE.IL is set */
|
||||
bool pstate_il;
|
||||
/*
|
||||
* >= 0, a copy of PSTATE.BTYPE, which will be 0 without v8.5-BTI.
|
||||
* < 0, set by the current instruction.
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue