target-arm queue:

* raspi boards: some cleanup
  * raspi: implement the bcm2835 system timer device
  * raspi: implement a dummy thermal sensor
  * misc devices: switch to ptimer transaction API
  * cache TB flag state to improve performance of cpu_get_tb_cpu_state
  * aspeed: Add an AST2600 eval board
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAl2y5m0ZHHBldGVyLm1h
 eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3hDGEACjvjKX9w02BEhcfnLlXuuN
 DM9AHZnprTQThsbA1KRR8UmHaY+Y4rTE9KqhLH9Ym0QIjO7CXlWniDYS5zA7aLuz
 Lo+6b39QZt0QZsTygWzzO3efHQvI0+z3wikk+cZm2RVeVs6dQggKjO7P3jzkp30Y
 ncMQVPT3jokN5++NpebqZk+6iesIH2nYxdjxwJNbgmEtU9MBk1C+6u8vo7vOJjqZ
 VJSA91esKkHgNSi+NQKSGk8fO+8cTw+7OqJS6ssH5K6/ndI59EgueKS4mt9WCKqb
 gfy+/mukKegVA4jd6NYNRsFKtOR1xqkwJViTpXiCb6bBMDS4J14x9KGaUISW0gMn
 urGrbvwq985HvZGIXqUH3GX7IwEHbFBgwaRl0aPmvJ+H24okEhSRWgw4V9ReLPIO
 GDoSr1gHHR88uo7v5F/Bu6OE3qRGqEvAG3ujiHHET9F3ilk1aUxgos41YkBriQbm
 pDwrP7kX1oUlEmeGmdRicxMFy304rlXtnT1qF6aMQz9k93R37p6Fr1q2jAFCsX/V
 p9udeX+fv1FIcEThHXIC6KEyGgldp38qRD5cTwcRpALyCvVBB3HLYEb7oIbfw7mn
 pUod2jZX2U1YAFWrXwc4DbRe6iDQs8wfKz/iuF44OW0Yy78iIaNqyhB70UA3F1V+
 WxIJs1FUEylaaypzkPwVBA==
 =hcWd
 -----END PGP SIGNATURE-----

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

target-arm queue:
 * raspi boards: some cleanup
 * raspi: implement the bcm2835 system timer device
 * raspi: implement a dummy thermal sensor
 * misc devices: switch to ptimer transaction API
 * cache TB flag state to improve performance of cpu_get_tb_cpu_state
 * aspeed: Add an AST2600 eval board

# gpg: Signature made Fri 25 Oct 2019 13:11:25 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-20191025: (42 commits)
  hw/arm/highbank: Use AddressSpace when using write_secondary_boot()
  hw/arm/raspi: Use AddressSpace when using arm_boot::write_secondary_boot
  hw/arm/bcm2836: Rename cpus[] as cpu[].core
  hw/arm/bcm2836: Make the SoC code modular
  hw/arm/bcm2835_peripherals: Use the SYS_timer
  hw/timer/bcm2835: Add the BCM2835 SYS_timer
  hw/arm/bcm2835_peripherals: Use the thermal sensor block
  hw/misc/bcm2835_thermal: Add a dummy BCM2835 thermal sensor
  hw/watchdog/milkymist-sysctl.c: Switch to transaction-based ptimer API
  hw/m68k/mcf5206.c: Switch to transaction-based ptimer API
  hw/timer/grlib_gptimer.c: Switch to transaction-based ptimer API
  hw/timer/slavio_timer.c: Switch to transaction-based ptimer API
  hw/timer/slavio_timer: Remove useless check for NULL t->timer
  hw/dma/xilinx_axidma.c: Switch to transaction-based ptimer API
  hw/timer/xilinx_timer.c: Switch to transaction-based ptimer API
  hw/net/fsl_etsec/etsec.c: Switch to transaction-based ptimer API
  target/arm: Rely on hflags correct in cpu_get_tb_cpu_state
  linux-user/arm: Rebuild hflags for TARGET_WORDS_BIGENDIAN
  linux-user/aarch64: Rebuild hflags for TARGET_WORDS_BIGENDIAN
  target/arm: Rebuild hflags for M-profile NVIC
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2019-10-25 13:12:16 +01:00
commit 7bc8f97342
40 changed files with 945 additions and 261 deletions

View File

@ -88,6 +88,10 @@ struct AspeedBoardState {
/* Witherspoon hardware value: 0xF10AD216 (but use romulus definition) */
#define WITHERSPOON_BMC_HW_STRAP1 ROMULUS_BMC_HW_STRAP1
/* AST2600 evb hardware value */
#define AST2600_EVB_HW_STRAP1 0x000000C0
#define AST2600_EVB_HW_STRAP2 0x00000003
/*
* The max ram region is for firmwares that scan the address space
* with load/store to guess how much RAM the SoC has.
@ -187,6 +191,8 @@ static void aspeed_board_init(MachineState *machine,
&error_abort);
object_property_set_int(OBJECT(&bmc->soc), cfg->hw_strap1, "hw-strap1",
&error_abort);
object_property_set_int(OBJECT(&bmc->soc), cfg->hw_strap2, "hw-strap2",
&error_abort);
object_property_set_int(OBJECT(&bmc->soc), cfg->num_cs, "num-cs",
&error_abort);
object_property_set_int(OBJECT(&bmc->soc), machine->smp.cpus, "num-cpus",
@ -308,6 +314,12 @@ static void ast2500_evb_i2c_init(AspeedBoardState *bmc)
i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), "ds1338", 0x32);
}
static void ast2600_evb_i2c_init(AspeedBoardState *bmc)
{
/* Start with some devices on our I2C busses */
ast2500_evb_i2c_init(bmc);
}
static void romulus_bmc_i2c_init(AspeedBoardState *bmc)
{
AspeedSoCState *soc = &bmc->soc;
@ -455,6 +467,17 @@ static const AspeedBoardConfig aspeed_boards[] = {
.num_cs = 2,
.i2c_init = witherspoon_bmc_i2c_init,
.ram = 512 * MiB,
}, {
.name = MACHINE_TYPE_NAME("ast2600-evb"),
.desc = "Aspeed AST2600 EVB (Cortex A7)",
.soc_name = "ast2600-a0",
.hw_strap1 = AST2600_EVB_HW_STRAP1,
.hw_strap2 = AST2600_EVB_HW_STRAP2,
.fmc_model = "w25q512jv",
.spi_model = "mx66u51235f",
.num_cs = 1,
.i2c_init = ast2600_evb_i2c_init,
.ram = 1 * GiB,
},
};

View File

@ -58,6 +58,10 @@ static void bcm2835_peripherals_init(Object *obj)
/* Interrupt Controller */
sysbus_init_child_obj(obj, "ic", &s->ic, sizeof(s->ic), TYPE_BCM2835_IC);
/* SYS Timer */
sysbus_init_child_obj(obj, "systimer", &s->systmr, sizeof(s->systmr),
TYPE_BCM2835_SYSTIMER);
/* UART0 */
sysbus_init_child_obj(obj, "uart0", &s->uart0, sizeof(s->uart0),
TYPE_PL011);
@ -111,6 +115,10 @@ static void bcm2835_peripherals_init(Object *obj)
object_property_add_const_link(OBJECT(&s->dma), "dma-mr",
OBJECT(&s->gpu_bus_mr), &error_abort);
/* Thermal */
sysbus_init_child_obj(obj, "thermal", &s->thermal, sizeof(s->thermal),
TYPE_BCM2835_THERMAL);
/* GPIO */
sysbus_init_child_obj(obj, "gpio", &s->gpio, sizeof(s->gpio),
TYPE_BCM2835_GPIO);
@ -167,6 +175,18 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->ic), 0));
sysbus_pass_irq(SYS_BUS_DEVICE(s), SYS_BUS_DEVICE(&s->ic));
/* Sys Timer */
object_property_set_bool(OBJECT(&s->systmr), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
memory_region_add_subregion(&s->peri_mr, ST_OFFSET,
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->systmr), 0));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->systmr), 0,
qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_ARM_IRQ,
INTERRUPT_ARM_TIMER));
/* UART0 */
qdev_prop_set_chr(DEVICE(&s->uart0), "chardev", serial_hd(0));
object_property_set_bool(OBJECT(&s->uart0), true, "realized", &err);
@ -321,6 +341,15 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
INTERRUPT_DMA0 + n));
}
/* THERMAL */
object_property_set_bool(OBJECT(&s->thermal), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
memory_region_add_subregion(&s->peri_mr, THERMAL_OFFSET,
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->thermal), 0));
/* GPIO */
object_property_set_bool(OBJECT(&s->gpio), true, "realized", &err);
if (err) {
@ -339,7 +368,6 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
}
create_unimp(s, &s->armtmr, "bcm2835-sp804", ARMCTRL_TIMER0_1_OFFSET, 0x40);
create_unimp(s, &s->systmr, "bcm2835-systimer", ST_OFFSET, 0x20);
create_unimp(s, &s->cprman, "bcm2835-cprman", CPRMAN_OFFSET, 0x1000);
create_unimp(s, &s->a2w, "bcm2835-a2w", A2W_OFFSET, 0x1000);
create_unimp(s, &s->i2s, "bcm2835-i2s", I2S_OFFSET, 0x100);

View File

@ -16,15 +16,11 @@
#include "hw/arm/raspi_platform.h"
#include "hw/sysbus.h"
/* Peripheral base address seen by the CPU */
#define BCM2836_PERI_BASE 0x3F000000
/* "QA7" (Pi2) interrupt controller and mailboxes etc. */
#define BCM2836_CONTROL_BASE 0x40000000
struct BCM283XInfo {
const char *name;
const char *cpu_type;
hwaddr peri_base; /* Peripheral base address seen by the CPU */
hwaddr ctrl_base; /* Interrupt controller and mailboxes etc. */
int clusterid;
};
@ -32,12 +28,16 @@ static const BCM283XInfo bcm283x_socs[] = {
{
.name = TYPE_BCM2836,
.cpu_type = ARM_CPU_TYPE_NAME("cortex-a7"),
.peri_base = 0x3f000000,
.ctrl_base = 0x40000000,
.clusterid = 0xf,
},
#ifdef TARGET_AARCH64
{
.name = TYPE_BCM2837,
.cpu_type = ARM_CPU_TYPE_NAME("cortex-a53"),
.peri_base = 0x3f000000,
.ctrl_base = 0x40000000,
.clusterid = 0x0,
},
#endif
@ -51,8 +51,9 @@ static void bcm2836_init(Object *obj)
int n;
for (n = 0; n < BCM283X_NCPUS; n++) {
object_initialize_child(obj, "cpu[*]", &s->cpus[n], sizeof(s->cpus[n]),
info->cpu_type, &error_abort, NULL);
object_initialize_child(obj, "cpu[*]", &s->cpu[n].core,
sizeof(s->cpu[n].core), info->cpu_type,
&error_abort, NULL);
}
sysbus_init_child_obj(obj, "control", &s->control, sizeof(s->control),
@ -104,7 +105,7 @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
}
sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->peripherals), 0,
BCM2836_PERI_BASE, 1);
info->peri_base, 1);
/* bcm2836 interrupt controller (and mailboxes, etc.) */
object_property_set_bool(OBJECT(&s->control), true, "realized", &err);
@ -113,7 +114,7 @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->control), 0, BCM2836_CONTROL_BASE);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->control), 0, info->ctrl_base);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0,
qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-irq", 0));
@ -122,11 +123,11 @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
for (n = 0; n < BCM283X_NCPUS; n++) {
/* TODO: this should be converted to a property of ARM_CPU */
s->cpus[n].mp_affinity = (info->clusterid << 8) | n;
s->cpu[n].core.mp_affinity = (info->clusterid << 8) | n;
/* set periphbase/CBAR value for CPU-local registers */
object_property_set_int(OBJECT(&s->cpus[n]),
BCM2836_PERI_BASE + MSYNC_OFFSET,
object_property_set_int(OBJECT(&s->cpu[n].core),
info->peri_base,
"reset-cbar", &err);
if (err) {
error_propagate(errp, err);
@ -134,14 +135,15 @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
}
/* start powered off if not enabled */
object_property_set_bool(OBJECT(&s->cpus[n]), n >= s->enabled_cpus,
object_property_set_bool(OBJECT(&s->cpu[n].core), n >= s->enabled_cpus,
"start-powered-off", &err);
if (err) {
error_propagate(errp, err);
return;
}
object_property_set_bool(OBJECT(&s->cpus[n]), true, "realized", &err);
object_property_set_bool(OBJECT(&s->cpu[n].core), true,
"realized", &err);
if (err) {
error_propagate(errp, err);
return;
@ -149,18 +151,18 @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
/* Connect irq/fiq outputs from the interrupt controller. */
qdev_connect_gpio_out_named(DEVICE(&s->control), "irq", n,
qdev_get_gpio_in(DEVICE(&s->cpus[n]), ARM_CPU_IRQ));
qdev_get_gpio_in(DEVICE(&s->cpu[n].core), ARM_CPU_IRQ));
qdev_connect_gpio_out_named(DEVICE(&s->control), "fiq", n,
qdev_get_gpio_in(DEVICE(&s->cpus[n]), ARM_CPU_FIQ));
qdev_get_gpio_in(DEVICE(&s->cpu[n].core), ARM_CPU_FIQ));
/* Connect timers from the CPU to the interrupt controller */
qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_PHYS,
qdev_connect_gpio_out(DEVICE(&s->cpu[n].core), GTIMER_PHYS,
qdev_get_gpio_in_named(DEVICE(&s->control), "cntpnsirq", n));
qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_VIRT,
qdev_connect_gpio_out(DEVICE(&s->cpu[n].core), GTIMER_VIRT,
qdev_get_gpio_in_named(DEVICE(&s->control), "cntvirq", n));
qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_HYP,
qdev_connect_gpio_out(DEVICE(&s->cpu[n].core), GTIMER_HYP,
qdev_get_gpio_in_named(DEVICE(&s->control), "cnthpirq", n));
qdev_connect_gpio_out(DEVICE(&s->cpus[n]), GTIMER_SEC,
qdev_connect_gpio_out(DEVICE(&s->cpu[n].core), GTIMER_SEC,
qdev_get_gpio_in_named(DEVICE(&s->control), "cntpsirq", n));
}
}

View File

@ -78,7 +78,8 @@ static void hb_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info)
for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
smpboot[n] = tswap32(smpboot[n]);
}
rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), SMP_BOOT_ADDR);
rom_add_blob_fixed_as("smpboot", smpboot, sizeof(smpboot), SMP_BOOT_ADDR,
arm_boot_address_space(cpu, info));
}
static void hb_reset_secondary(ARMCPU *cpu, const struct arm_boot_info *info)

View File

@ -60,12 +60,14 @@ static void write_smpboot(ARMCPU *cpu, const struct arm_boot_info *info)
QEMU_BUILD_BUG_ON((BOARDSETUP_ADDR & 0xf) != 0
|| (BOARDSETUP_ADDR >> 4) >= 0x100);
rom_add_blob_fixed("raspi_smpboot", smpboot, sizeof(smpboot),
info->smp_loader_start);
rom_add_blob_fixed_as("raspi_smpboot", smpboot, sizeof(smpboot),
info->smp_loader_start,
arm_boot_address_space(cpu, info));
}
static void write_smpboot64(ARMCPU *cpu, const struct arm_boot_info *info)
{
AddressSpace *as = arm_boot_address_space(cpu, info);
/* Unlike the AArch32 version we don't need to call the board setup hook.
* The mechanism for doing the spin-table is also entirely different.
* We must have four 64-bit fields at absolute addresses
@ -92,10 +94,10 @@ static void write_smpboot64(ARMCPU *cpu, const struct arm_boot_info *info)
0, 0, 0, 0
};
rom_add_blob_fixed("raspi_smpboot", smpboot, sizeof(smpboot),
info->smp_loader_start);
rom_add_blob_fixed("raspi_spintables", spintables, sizeof(spintables),
SPINTABLE_ADDR);
rom_add_blob_fixed_as("raspi_smpboot", smpboot, sizeof(smpboot),
info->smp_loader_start, as);
rom_add_blob_fixed_as("raspi_spintables", spintables, sizeof(spintables),
SPINTABLE_ADDR, as);
}
static void write_board_setup(ARMCPU *cpu, const struct arm_boot_info *info)

View File

@ -31,7 +31,6 @@
#include "hw/ptimer.h"
#include "hw/qdev-properties.h"
#include "qemu/log.h"
#include "qemu/main-loop.h"
#include "qemu/module.h"
#include "hw/stream.h"
@ -104,7 +103,6 @@ enum {
};
struct Stream {
QEMUBH *bh;
ptimer_state *ptimer;
qemu_irq irq;
@ -242,6 +240,7 @@ static void stream_complete(struct Stream *s)
unsigned int comp_delay;
/* Start the delayed timer. */
ptimer_transaction_begin(s->ptimer);
comp_delay = s->regs[R_DMACR] >> 24;
if (comp_delay) {
ptimer_stop(s->ptimer);
@ -255,6 +254,7 @@ static void stream_complete(struct Stream *s)
s->regs[R_DMASR] |= DMASR_IOC_IRQ;
stream_reload_complete_cnt(s);
}
ptimer_transaction_commit(s->ptimer);
}
static void stream_process_mem2s(struct Stream *s, StreamSlave *tx_data_dev,
@ -551,9 +551,10 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp)
struct Stream *st = &s->streams[i];
st->nr = i;
st->bh = qemu_bh_new(timer_hit, st);
st->ptimer = ptimer_init_with_bh(st->bh, PTIMER_POLICY_DEFAULT);
st->ptimer = ptimer_init(timer_hit, st, PTIMER_POLICY_DEFAULT);
ptimer_transaction_begin(st->ptimer);
ptimer_set_freq(st->ptimer, s->freqhz);
ptimer_transaction_commit(st->ptimer);
}
return;

View File

@ -733,13 +733,13 @@ static void aspeed_gpio_get_pin(Object *obj, Visitor *v, const char *name,
{
int pin = 0xfff;
bool level = true;
char group[3];
char group[4];
AspeedGPIOState *s = ASPEED_GPIO(obj);
int set_idx, group_idx = 0;
if (sscanf(name, "gpio%2[A-Z]%1d", group, &pin) != 2) {
/* 1.8V gpio */
if (sscanf(name, "gpio%3s%1d", group, &pin) != 2) {
if (sscanf(name, "gpio%3[18A-E]%1d", group, &pin) != 2) {
error_setg(errp, "%s: error reading %s", __func__, name);
return;
}
@ -760,7 +760,7 @@ static void aspeed_gpio_set_pin(Object *obj, Visitor *v, const char *name,
Error *local_err = NULL;
bool level;
int pin = 0xfff;
char group[3];
char group[4];
AspeedGPIOState *s = ASPEED_GPIO(obj);
int set_idx, group_idx = 0;
@ -771,7 +771,7 @@ static void aspeed_gpio_set_pin(Object *obj, Visitor *v, const char *name,
}
if (sscanf(name, "gpio%2[A-Z]%1d", group, &pin) != 2) {
/* 1.8V gpio */
if (sscanf(name, "gpio%3s%1d", group, &pin) != 2) {
if (sscanf(name, "gpio%3[18A-E]%1d", group, &pin) != 2) {
error_setg(errp, "%s: error reading %s", __func__, name);
return;
}

View File

@ -2251,7 +2251,7 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr,
}
}
nvic_irq_update(s);
return MEMTX_OK;
goto exit_ok;
case 0x200 ... 0x23f: /* NVIC Set pend */
/* the special logic in armv7m_nvic_set_pending()
* is not needed since IRQs are never escalated
@ -2269,9 +2269,9 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr,
}
}
nvic_irq_update(s);
return MEMTX_OK;
goto exit_ok;
case 0x300 ... 0x33f: /* NVIC Active */
return MEMTX_OK; /* R/O */
goto exit_ok; /* R/O */
case 0x400 ... 0x5ef: /* NVIC Priority */
startvec = (offset - 0x400) + NVIC_FIRST_IRQ; /* vector # */
@ -2281,10 +2281,10 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr,
}
}
nvic_irq_update(s);
return MEMTX_OK;
goto exit_ok;
case 0xd18 ... 0xd1b: /* System Handler Priority (SHPR1) */
if (!arm_feature(&s->cpu->env, ARM_FEATURE_M_MAIN)) {
return MEMTX_OK;
goto exit_ok;
}
/* fall through */
case 0xd1c ... 0xd23: /* System Handler Priority (SHPR2, SHPR3) */
@ -2299,10 +2299,10 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr,
set_prio(s, hdlidx, sbank, newprio);
}
nvic_irq_update(s);
return MEMTX_OK;
goto exit_ok;
case 0xd28 ... 0xd2b: /* Configurable Fault Status (CFSR) */
if (!arm_feature(&s->cpu->env, ARM_FEATURE_M_MAIN)) {
return MEMTX_OK;
goto exit_ok;
}
/* All bits are W1C, so construct 32 bit value with 0s in
* the parts not written by the access size
@ -2322,15 +2322,19 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr,
*/
s->cpu->env.v7m.cfsr[M_REG_NS] &= ~(value & R_V7M_CFSR_BFSR_MASK);
}
return MEMTX_OK;
goto exit_ok;
}
if (size == 4) {
nvic_writel(s, offset, value, attrs);
return MEMTX_OK;
goto exit_ok;
}
qemu_log_mask(LOG_GUEST_ERROR,
"NVIC: Bad write of size %d at offset 0x%x\n", size, offset);
/* This is UNPREDICTABLE; treat as RAZ/WI */
exit_ok:
/* Ensure any changes made are reflected in the cached hflags. */
arm_rebuild_hflags(&s->cpu->env);
return MEMTX_OK;
}

View File

@ -8,7 +8,6 @@
#include "qemu/osdep.h"
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
#include "cpu.h"
#include "hw/hw.h"
#include "hw/irq.h"
@ -57,10 +56,12 @@ static void m5206_timer_recalibrate(m5206_timer_state *s)
int prescale;
int mode;
ptimer_transaction_begin(s->timer);
ptimer_stop(s->timer);
if ((s->tmr & TMR_RST) == 0)
return;
if ((s->tmr & TMR_RST) == 0) {
goto exit;
}
prescale = (s->tmr >> 8) + 1;
mode = (s->tmr >> 1) & 3;
@ -78,6 +79,8 @@ static void m5206_timer_recalibrate(m5206_timer_state *s)
ptimer_set_limit(s->timer, s->trr, 0);
ptimer_run(s->timer, 0);
exit:
ptimer_transaction_commit(s->timer);
}
static void m5206_timer_trigger(void *opaque)
@ -123,7 +126,9 @@ static void m5206_timer_write(m5206_timer_state *s, uint32_t addr, uint32_t val)
s->tcr = val;
break;
case 0xc:
ptimer_transaction_begin(s->timer);
ptimer_set_count(s->timer, val);
ptimer_transaction_commit(s->timer);
break;
case 0x11:
s->ter &= ~val;
@ -137,11 +142,9 @@ static void m5206_timer_write(m5206_timer_state *s, uint32_t addr, uint32_t val)
static m5206_timer_state *m5206_timer_init(qemu_irq irq)
{
m5206_timer_state *s;
QEMUBH *bh;
s = g_new0(m5206_timer_state, 1);
bh = qemu_bh_new(m5206_timer_trigger, s);
s->timer = ptimer_init_with_bh(bh, PTIMER_POLICY_DEFAULT);
s->timer = ptimer_init(m5206_timer_trigger, s, PTIMER_POLICY_DEFAULT);
s->irq = irq;
m5206_timer_reset(s);
return s;

View File

@ -53,6 +53,7 @@ common-obj-$(CONFIG_OMAP) += omap_tap.o
common-obj-$(CONFIG_RASPI) += bcm2835_mbox.o
common-obj-$(CONFIG_RASPI) += bcm2835_property.o
common-obj-$(CONFIG_RASPI) += bcm2835_rng.o
common-obj-$(CONFIG_RASPI) += bcm2835_thermal.o
common-obj-$(CONFIG_SLAVIO) += slavio_misc.o
common-obj-$(CONFIG_ZYNQ) += zynq_slcr.o
common-obj-$(CONFIG_ZYNQ) += zynq-xadc.o

135
hw/misc/bcm2835_thermal.c Normal file
View File

@ -0,0 +1,135 @@
/*
* BCM2835 dummy thermal sensor
*
* Copyright (C) 2019 Philippe Mathieu-Daudé <f4bug@amsat.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qapi/error.h"
#include "hw/misc/bcm2835_thermal.h"
#include "hw/registerfields.h"
#include "migration/vmstate.h"
REG32(CTL, 0)
FIELD(CTL, POWER_DOWN, 0, 1)
FIELD(CTL, RESET, 1, 1)
FIELD(CTL, BANDGAP_CTRL, 2, 3)
FIELD(CTL, INTERRUPT_ENABLE, 5, 1)
FIELD(CTL, DIRECT, 6, 1)
FIELD(CTL, INTERRUPT_CLEAR, 7, 1)
FIELD(CTL, HOLD, 8, 10)
FIELD(CTL, RESET_DELAY, 18, 8)
FIELD(CTL, REGULATOR_ENABLE, 26, 1)
REG32(STAT, 4)
FIELD(STAT, DATA, 0, 10)
FIELD(STAT, VALID, 10, 1)
FIELD(STAT, INTERRUPT, 11, 1)
#define THERMAL_OFFSET_C 412
#define THERMAL_COEFF (-0.538f)
static uint16_t bcm2835_thermal_temp2adc(int temp_C)
{
return (temp_C - THERMAL_OFFSET_C) / THERMAL_COEFF;
}
static uint64_t bcm2835_thermal_read(void *opaque, hwaddr addr, unsigned size)
{
Bcm2835ThermalState *s = BCM2835_THERMAL(opaque);
uint32_t val = 0;
switch (addr) {
case A_CTL:
val = s->ctl;
break;
case A_STAT:
/* Temperature is constantly 25°C. */
val = FIELD_DP32(bcm2835_thermal_temp2adc(25), STAT, VALID, true);
break;
default:
/* MemoryRegionOps are aligned, so this can not happen. */
g_assert_not_reached();
}
return val;
}
static void bcm2835_thermal_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size)
{
Bcm2835ThermalState *s = BCM2835_THERMAL(opaque);
switch (addr) {
case A_CTL:
s->ctl = value;
break;
case A_STAT:
qemu_log_mask(LOG_GUEST_ERROR, "%s: write 0x%" PRIx64
" to 0x%" HWADDR_PRIx "\n",
__func__, value, addr);
break;
default:
/* MemoryRegionOps are aligned, so this can not happen. */
g_assert_not_reached();
}
}
static const MemoryRegionOps bcm2835_thermal_ops = {
.read = bcm2835_thermal_read,
.write = bcm2835_thermal_write,
.impl.max_access_size = 4,
.valid.min_access_size = 4,
.endianness = DEVICE_NATIVE_ENDIAN,
};
static void bcm2835_thermal_reset(DeviceState *dev)
{
Bcm2835ThermalState *s = BCM2835_THERMAL(dev);
s->ctl = 0;
}
static void bcm2835_thermal_realize(DeviceState *dev, Error **errp)
{
Bcm2835ThermalState *s = BCM2835_THERMAL(dev);
memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_thermal_ops,
s, TYPE_BCM2835_THERMAL, 8);
sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
}
static const VMStateDescription bcm2835_thermal_vmstate = {
.name = "bcm2835_thermal",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(ctl, Bcm2835ThermalState),
VMSTATE_END_OF_LIST()
}
};
static void bcm2835_thermal_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = bcm2835_thermal_realize;
dc->reset = bcm2835_thermal_reset;
dc->vmsd = &bcm2835_thermal_vmstate;
}
static const TypeInfo bcm2835_thermal_info = {
.name = TYPE_BCM2835_THERMAL,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(Bcm2835ThermalState),
.class_init = bcm2835_thermal_class_init,
};
static void bcm2835_thermal_register_types(void)
{
type_register_static(&bcm2835_thermal_info);
}
type_init(bcm2835_thermal_register_types)

View File

@ -34,7 +34,6 @@
#include "etsec.h"
#include "registers.h"
#include "qemu/log.h"
#include "qemu/main-loop.h"
#include "qemu/module.h"
/* #define HEX_DUMP */
@ -195,9 +194,11 @@ static void write_dmactrl(eTSEC *etsec,
if (!(value & DMACTRL_WOP)) {
/* Start polling */
ptimer_transaction_begin(etsec->ptimer);
ptimer_stop(etsec->ptimer);
ptimer_set_count(etsec->ptimer, 1);
ptimer_run(etsec->ptimer, 1);
ptimer_transaction_commit(etsec->ptimer);
}
}
@ -391,10 +392,10 @@ static void etsec_realize(DeviceState *dev, Error **errp)
object_get_typename(OBJECT(dev)), dev->id, etsec);
qemu_format_nic_info_str(qemu_get_queue(etsec->nic), etsec->conf.macaddr.a);
etsec->bh = qemu_bh_new(etsec_timer_hit, etsec);
etsec->ptimer = ptimer_init_with_bh(etsec->bh, PTIMER_POLICY_DEFAULT);
etsec->ptimer = ptimer_init(etsec_timer_hit, etsec, PTIMER_POLICY_DEFAULT);
ptimer_transaction_begin(etsec->ptimer);
ptimer_set_freq(etsec->ptimer, 100);
ptimer_transaction_commit(etsec->ptimer);
}
static void etsec_instance_init(Object *obj)

View File

@ -141,7 +141,6 @@ typedef struct eTSEC {
uint16_t phy_control;
/* Polling */
QEMUBH *bh;
struct ptimer_state *ptimer;
/* Whether we should flush the rx queue when buffer becomes available. */

View File

@ -47,3 +47,4 @@ common-obj-$(CONFIG_SUN4V_RTC) += sun4v-rtc.o
common-obj-$(CONFIG_CMSDK_APB_TIMER) += cmsdk-apb-timer.o
common-obj-$(CONFIG_CMSDK_APB_DUALTIMER) += cmsdk-apb-dualtimer.o
common-obj-$(CONFIG_MSF2) += mss-timer.o
common-obj-$(CONFIG_RASPI) += bcm2835_systmr.o

163
hw/timer/bcm2835_systmr.c Normal file
View File

@ -0,0 +1,163 @@
/*
* BCM2835 SYS timer emulation
*
* Copyright (C) 2019 Philippe Mathieu-Daudé <f4bug@amsat.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Datasheet: BCM2835 ARM Peripherals (C6357-M-1398)
* https://www.raspberrypi.org/app/uploads/2012/02/BCM2835-ARM-Peripherals.pdf
*
* Only the free running 64-bit counter is implemented.
* The 4 COMPARE registers and the interruption are not implemented.
*/
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qemu/timer.h"
#include "hw/timer/bcm2835_systmr.h"
#include "hw/registerfields.h"
#include "migration/vmstate.h"
#include "trace.h"
REG32(CTRL_STATUS, 0x00)
REG32(COUNTER_LOW, 0x04)
REG32(COUNTER_HIGH, 0x08)
REG32(COMPARE0, 0x0c)
REG32(COMPARE1, 0x10)
REG32(COMPARE2, 0x14)
REG32(COMPARE3, 0x18)
static void bcm2835_systmr_update_irq(BCM2835SystemTimerState *s)
{
bool enable = !!s->reg.status;
trace_bcm2835_systmr_irq(enable);
qemu_set_irq(s->irq, enable);
}
static void bcm2835_systmr_update_compare(BCM2835SystemTimerState *s,
unsigned timer_index)
{
/* TODO fow now, since neither Linux nor U-boot use these timers. */
qemu_log_mask(LOG_UNIMP, "COMPARE register %u not implemented\n",
timer_index);
}
static uint64_t bcm2835_systmr_read(void *opaque, hwaddr offset,
unsigned size)
{
BCM2835SystemTimerState *s = BCM2835_SYSTIMER(opaque);
uint64_t r = 0;
switch (offset) {
case A_CTRL_STATUS:
r = s->reg.status;
break;
case A_COMPARE0 ... A_COMPARE3:
r = s->reg.compare[(offset - A_COMPARE0) >> 2];
break;
case A_COUNTER_LOW:
case A_COUNTER_HIGH:
/* Free running counter at 1MHz */
r = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL);
r >>= 8 * (offset - A_COUNTER_LOW);
r &= UINT32_MAX;
break;
default:
qemu_log_mask(LOG_GUEST_ERROR, "%s: bad offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
break;
}
trace_bcm2835_systmr_read(offset, r);
return r;
}
static void bcm2835_systmr_write(void *opaque, hwaddr offset,
uint64_t value, unsigned size)
{
BCM2835SystemTimerState *s = BCM2835_SYSTIMER(opaque);
trace_bcm2835_systmr_write(offset, value);
switch (offset) {
case A_CTRL_STATUS:
s->reg.status &= ~value; /* Ack */
bcm2835_systmr_update_irq(s);
break;
case A_COMPARE0 ... A_COMPARE3:
s->reg.compare[(offset - A_COMPARE0) >> 2] = value;
bcm2835_systmr_update_compare(s, (offset - A_COMPARE0) >> 2);
break;
case A_COUNTER_LOW:
case A_COUNTER_HIGH:
qemu_log_mask(LOG_GUEST_ERROR, "%s: read-only ofs 0x%" HWADDR_PRIx "\n",
__func__, offset);
break;
default:
qemu_log_mask(LOG_GUEST_ERROR, "%s: bad offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
break;
}
}
static const MemoryRegionOps bcm2835_systmr_ops = {
.read = bcm2835_systmr_read,
.write = bcm2835_systmr_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.impl = {
.min_access_size = 4,
.max_access_size = 4,
},
};
static void bcm2835_systmr_reset(DeviceState *dev)
{
BCM2835SystemTimerState *s = BCM2835_SYSTIMER(dev);
memset(&s->reg, 0, sizeof(s->reg));
}
static void bcm2835_systmr_realize(DeviceState *dev, Error **errp)
{
BCM2835SystemTimerState *s = BCM2835_SYSTIMER(dev);
memory_region_init_io(&s->iomem, OBJECT(dev), &bcm2835_systmr_ops,
s, "bcm2835-sys-timer", 0x20);
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
}
static const VMStateDescription bcm2835_systmr_vmstate = {
.name = "bcm2835_sys_timer",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(reg.status, BCM2835SystemTimerState),
VMSTATE_UINT32_ARRAY(reg.compare, BCM2835SystemTimerState, 4),
VMSTATE_END_OF_LIST()
}
};
static void bcm2835_systmr_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = bcm2835_systmr_realize;
dc->reset = bcm2835_systmr_reset;
dc->vmsd = &bcm2835_systmr_vmstate;
}
static const TypeInfo bcm2835_systmr_info = {
.name = TYPE_BCM2835_SYSTIMER,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(BCM2835SystemTimerState),
.class_init = bcm2835_systmr_class_init,
};
static void bcm2835_systmr_register_types(void)
{
type_register_static(&bcm2835_systmr_info);
}
type_init(bcm2835_systmr_register_types);

View File

@ -29,7 +29,6 @@
#include "hw/irq.h"
#include "hw/ptimer.h"
#include "hw/qdev-properties.h"
#include "qemu/main-loop.h"
#include "qemu/module.h"
#include "trace.h"
@ -63,7 +62,6 @@ typedef struct GPTimer GPTimer;
typedef struct GPTimerUnit GPTimerUnit;
struct GPTimer {
QEMUBH *bh;
struct ptimer_state *ptimer;
qemu_irq irq;
@ -93,6 +91,17 @@ struct GPTimerUnit {
uint32_t config;
};
static void grlib_gptimer_tx_begin(GPTimer *timer)
{
ptimer_transaction_begin(timer->ptimer);
}
static void grlib_gptimer_tx_commit(GPTimer *timer)
{
ptimer_transaction_commit(timer->ptimer);
}
/* Must be called within grlib_gptimer_tx_begin/commit block */
static void grlib_gptimer_enable(GPTimer *timer)
{
assert(timer != NULL);
@ -115,6 +124,7 @@ static void grlib_gptimer_enable(GPTimer *timer)
ptimer_run(timer->ptimer, 1);
}
/* Must be called within grlib_gptimer_tx_begin/commit block */
static void grlib_gptimer_restart(GPTimer *timer)
{
assert(timer != NULL);
@ -141,7 +151,9 @@ static void grlib_gptimer_set_scaler(GPTimerUnit *unit, uint32_t scaler)
trace_grlib_gptimer_set_scaler(scaler, value);
for (i = 0; i < unit->nr_timers; i++) {
ptimer_transaction_begin(unit->timers[i].ptimer);
ptimer_set_freq(unit->timers[i].ptimer, value);
ptimer_transaction_commit(unit->timers[i].ptimer);
}
}
@ -266,8 +278,10 @@ static void grlib_gptimer_write(void *opaque, hwaddr addr,
switch (timer_addr) {
case COUNTER_OFFSET:
trace_grlib_gptimer_writel(id, addr, value);
grlib_gptimer_tx_begin(&unit->timers[id]);
unit->timers[id].counter = value;
grlib_gptimer_enable(&unit->timers[id]);
grlib_gptimer_tx_commit(&unit->timers[id]);
return;
case COUNTER_RELOAD_OFFSET:
@ -291,6 +305,7 @@ static void grlib_gptimer_write(void *opaque, hwaddr addr,
/* gptimer_restart calls gptimer_enable, so if "enable" and "load"
bits are present, we just have to call restart. */
grlib_gptimer_tx_begin(&unit->timers[id]);
if (value & GPTIMER_LOAD) {
grlib_gptimer_restart(&unit->timers[id]);
} else if (value & GPTIMER_ENABLE) {
@ -301,6 +316,7 @@ static void grlib_gptimer_write(void *opaque, hwaddr addr,
value &= ~(GPTIMER_LOAD & GPTIMER_DEBUG_HALT);
unit->timers[id].config = value;
grlib_gptimer_tx_commit(&unit->timers[id]);
return;
default:
@ -344,9 +360,11 @@ static void grlib_gptimer_reset(DeviceState *d)
timer->counter = 0;
timer->reload = 0;
timer->config = 0;
ptimer_transaction_begin(timer->ptimer);
ptimer_stop(timer->ptimer);
ptimer_set_count(timer->ptimer, 0);
ptimer_set_freq(timer->ptimer, unit->freq_hz);
ptimer_transaction_commit(timer->ptimer);
}
}
@ -365,14 +383,16 @@ static void grlib_gptimer_realize(DeviceState *dev, Error **errp)
GPTimer *timer = &unit->timers[i];
timer->unit = unit;
timer->bh = qemu_bh_new(grlib_gptimer_hit, timer);
timer->ptimer = ptimer_init_with_bh(timer->bh, PTIMER_POLICY_DEFAULT);
timer->ptimer = ptimer_init(grlib_gptimer_hit, timer,
PTIMER_POLICY_DEFAULT);
timer->id = i;
/* One IRQ line for each timer */
sysbus_init_irq(sbd, &timer->irq);
ptimer_transaction_begin(timer->ptimer);
ptimer_set_freq(timer->ptimer, unit->freq_hz);
ptimer_transaction_commit(timer->ptimer);
}
memory_region_init_io(&unit->iomem, OBJECT(unit), &grlib_gptimer_ops,

View File

@ -31,7 +31,6 @@
#include "hw/ptimer.h"
#include "hw/qdev-properties.h"
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
#include "qemu/module.h"
enum {
@ -71,8 +70,6 @@ struct MilkymistSysctlState {
MemoryRegion regs_region;
QEMUBH *bh0;
QEMUBH *bh1;
ptimer_state *ptimer0;
ptimer_state *ptimer1;
@ -161,14 +158,19 @@ static void sysctl_write(void *opaque, hwaddr addr, uint64_t value,
s->regs[addr] = value;
break;
case R_TIMER0_COMPARE:
ptimer_transaction_begin(s->ptimer0);
ptimer_set_limit(s->ptimer0, value, 0);
s->regs[addr] = value;
ptimer_transaction_commit(s->ptimer0);
break;
case R_TIMER1_COMPARE:
ptimer_transaction_begin(s->ptimer1);
ptimer_set_limit(s->ptimer1, value, 0);
s->regs[addr] = value;
ptimer_transaction_commit(s->ptimer1);
break;
case R_TIMER0_CONTROL:
ptimer_transaction_begin(s->ptimer0);
s->regs[addr] = value;
if (s->regs[R_TIMER0_CONTROL] & CTRL_ENABLE) {
trace_milkymist_sysctl_start_timer0();
@ -179,8 +181,10 @@ static void sysctl_write(void *opaque, hwaddr addr, uint64_t value,
trace_milkymist_sysctl_stop_timer0();
ptimer_stop(s->ptimer0);
}
ptimer_transaction_commit(s->ptimer0);
break;
case R_TIMER1_CONTROL:
ptimer_transaction_begin(s->ptimer1);
s->regs[addr] = value;
if (s->regs[R_TIMER1_CONTROL] & CTRL_ENABLE) {
trace_milkymist_sysctl_start_timer1();
@ -191,6 +195,7 @@ static void sysctl_write(void *opaque, hwaddr addr, uint64_t value,
trace_milkymist_sysctl_stop_timer1();
ptimer_stop(s->ptimer1);
}
ptimer_transaction_commit(s->ptimer1);
break;
case R_ICAP:
sysctl_icap_write(s, value);
@ -263,8 +268,12 @@ static void milkymist_sysctl_reset(DeviceState *d)
s->regs[i] = 0;
}
ptimer_transaction_begin(s->ptimer0);
ptimer_stop(s->ptimer0);
ptimer_transaction_commit(s->ptimer0);
ptimer_transaction_begin(s->ptimer1);
ptimer_stop(s->ptimer1);
ptimer_transaction_commit(s->ptimer1);
/* defaults */
s->regs[R_ICAP] = ICAP_READY;
@ -292,13 +301,15 @@ static void milkymist_sysctl_realize(DeviceState *dev, Error **errp)
{
MilkymistSysctlState *s = MILKYMIST_SYSCTL(dev);
s->bh0 = qemu_bh_new(timer0_hit, s);
s->bh1 = qemu_bh_new(timer1_hit, s);
s->ptimer0 = ptimer_init_with_bh(s->bh0, PTIMER_POLICY_DEFAULT);
s->ptimer1 = ptimer_init_with_bh(s->bh1, PTIMER_POLICY_DEFAULT);
s->ptimer0 = ptimer_init(timer0_hit, s, PTIMER_POLICY_DEFAULT);
s->ptimer1 = ptimer_init(timer1_hit, s, PTIMER_POLICY_DEFAULT);
ptimer_transaction_begin(s->ptimer0);
ptimer_set_freq(s->ptimer0, s->freq_hz);
ptimer_transaction_commit(s->ptimer0);
ptimer_transaction_begin(s->ptimer1);
ptimer_set_freq(s->ptimer1, s->freq_hz);
ptimer_transaction_commit(s->ptimer1);
}
static const VMStateDescription vmstate_milkymist_sysctl = {

View File

@ -30,7 +30,6 @@
#include "hw/sysbus.h"
#include "migration/vmstate.h"
#include "trace.h"
#include "qemu/main-loop.h"
#include "qemu/module.h"
/*
@ -213,6 +212,7 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
saddr = addr >> 2;
switch (saddr) {
case TIMER_LIMIT:
ptimer_transaction_begin(t->timer);
if (slavio_timer_is_user(tc)) {
uint64_t count;
@ -227,15 +227,14 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
// set limit, reset counter
qemu_irq_lower(t->irq);
t->limit = val & TIMER_MAX_COUNT32;
if (t->timer) {
if (t->limit == 0) { /* free-run */
ptimer_set_limit(t->timer,
LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
} else {
ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 1);
}
if (t->limit == 0) { /* free-run */
ptimer_set_limit(t->timer,
LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
} else {
ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 1);
}
}
ptimer_transaction_commit(t->timer);
break;
case TIMER_COUNTER:
if (slavio_timer_is_user(tc)) {
@ -247,7 +246,9 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
t->reached = 0;
count = ((uint64_t)t->counthigh) << 32 | t->count;
trace_slavio_timer_mem_writel_limit(timer_index, count);
ptimer_transaction_begin(t->timer);
ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count));
ptimer_transaction_commit(t->timer);
} else {
trace_slavio_timer_mem_writel_counter_invalid();
}
@ -255,13 +256,16 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
case TIMER_COUNTER_NORST:
// set limit without resetting counter
t->limit = val & TIMER_MAX_COUNT32;
ptimer_transaction_begin(t->timer);
if (t->limit == 0) { /* free-run */
ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0);
} else {
ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 0);
}
ptimer_transaction_commit(t->timer);
break;
case TIMER_STATUS:
ptimer_transaction_begin(t->timer);
if (slavio_timer_is_user(tc)) {
// start/stop user counter
if (val & 1) {
@ -273,6 +277,7 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
}
}
t->run = val & 1;
ptimer_transaction_commit(t->timer);
break;
case TIMER_MODE:
if (timer_index == 0) {
@ -282,6 +287,7 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
unsigned int processor = 1 << i;
CPUTimerState *curr_timer = &s->cputimer[i + 1];
ptimer_transaction_begin(curr_timer->timer);
// check for a change in timer mode for this processor
if ((val & processor) != (s->cputimer_mode & processor)) {
if (val & processor) { // counter -> user timer
@ -308,6 +314,7 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
trace_slavio_timer_mem_writel_mode_counter(timer_index);
}
}
ptimer_transaction_commit(curr_timer->timer);
}
} else {
trace_slavio_timer_mem_writel_mode_invalid();
@ -367,10 +374,12 @@ static void slavio_timer_reset(DeviceState *d)
curr_timer->count = 0;
curr_timer->reached = 0;
if (i <= s->num_cpus) {
ptimer_transaction_begin(curr_timer->timer);
ptimer_set_limit(curr_timer->timer,
LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
ptimer_run(curr_timer->timer, 0);
curr_timer->run = 1;
ptimer_transaction_commit(curr_timer->timer);
}
}
s->cputimer_mode = 0;
@ -380,7 +389,6 @@ static void slavio_timer_init(Object *obj)
{
SLAVIO_TIMERState *s = SLAVIO_TIMER(obj);
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
QEMUBH *bh;
unsigned int i;
TimerContext *tc;
@ -392,9 +400,11 @@ static void slavio_timer_init(Object *obj)
tc->s = s;
tc->timer_index = i;
bh = qemu_bh_new(slavio_timer_irq, tc);
s->cputimer[i].timer = ptimer_init_with_bh(bh, PTIMER_POLICY_DEFAULT);
s->cputimer[i].timer = ptimer_init(slavio_timer_irq, tc,
PTIMER_POLICY_DEFAULT);
ptimer_transaction_begin(s->cputimer[i].timer);
ptimer_set_period(s->cputimer[i].timer, TIMER_PERIOD);
ptimer_transaction_commit(s->cputimer[i].timer);
size = i == 0 ? SYS_TIMER_SIZE : CPU_TIMER_SIZE;
snprintf(timer_name, sizeof(timer_name), "timer-%i", i);

View File

@ -87,3 +87,8 @@ pl031_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
pl031_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
pl031_alarm_raised(void) "alarm raised"
pl031_set_alarm(uint32_t ticks) "alarm set for %u ticks"
# bcm2835_systmr.c
bcm2835_systmr_irq(bool enable) "timer irq state %u"
bcm2835_systmr_read(uint64_t offset, uint64_t data) "timer read: offset 0x%" PRIx64 " data 0x%" PRIx64
bcm2835_systmr_write(uint64_t offset, uint64_t data) "timer write: offset 0x%" PRIx64 " data 0x%" PRIx64

View File

@ -28,7 +28,6 @@
#include "hw/ptimer.h"
#include "hw/qdev-properties.h"
#include "qemu/log.h"
#include "qemu/main-loop.h"
#include "qemu/module.h"
#define D(x)
@ -52,7 +51,6 @@
struct xlx_timer
{
QEMUBH *bh;
ptimer_state *ptimer;
void *parent;
int nr; /* for debug. */
@ -134,6 +132,7 @@ timer_read(void *opaque, hwaddr addr, unsigned int size)
return r;
}
/* Must be called inside ptimer transaction block */
static void timer_enable(struct xlx_timer *xt)
{
uint64_t count;
@ -174,8 +173,11 @@ timer_write(void *opaque, hwaddr addr,
value &= ~TCSR_TINT;
xt->regs[addr] = value & 0x7ff;
if (value & TCSR_ENT)
if (value & TCSR_ENT) {
ptimer_transaction_begin(xt->ptimer);
timer_enable(xt);
ptimer_transaction_commit(xt->ptimer);
}
break;
default:
@ -220,9 +222,10 @@ static void xilinx_timer_realize(DeviceState *dev, Error **errp)
xt->parent = t;
xt->nr = i;
xt->bh = qemu_bh_new(timer_hit, xt);
xt->ptimer = ptimer_init_with_bh(xt->bh, PTIMER_POLICY_DEFAULT);
xt->ptimer = ptimer_init(timer_hit, xt, PTIMER_POLICY_DEFAULT);
ptimer_transaction_begin(xt->ptimer);
ptimer_set_freq(xt->ptimer, t->freq_hz);
ptimer_transaction_commit(xt->ptimer);
}
memory_region_init_io(&t->mmio, OBJECT(t), &timer_ops, t, "xlnx.xps-timer",

View File

@ -18,6 +18,7 @@ typedef struct AspeedBoardConfig {
const char *desc;
const char *soc_name;
uint32_t hw_strap1;
uint32_t hw_strap2;
const char *fmc_model;
const char *spi_model;
uint32_t num_cs;

View File

@ -20,9 +20,11 @@
#include "hw/misc/bcm2835_property.h"
#include "hw/misc/bcm2835_rng.h"
#include "hw/misc/bcm2835_mbox.h"
#include "hw/misc/bcm2835_thermal.h"
#include "hw/sd/sdhci.h"
#include "hw/sd/bcm2835_sdhost.h"
#include "hw/gpio/bcm2835_gpio.h"
#include "hw/timer/bcm2835_systmr.h"
#include "hw/misc/unimp.h"
#define TYPE_BCM2835_PERIPHERALS "bcm2835-peripherals"
@ -38,7 +40,7 @@ typedef struct BCM2835PeripheralState {
MemoryRegion ram_alias[4];
qemu_irq irq, fiq;
UnimplementedDeviceState systmr;
BCM2835SystemTimerState systmr;
UnimplementedDeviceState armtmr;
UnimplementedDeviceState cprman;
UnimplementedDeviceState a2w;
@ -53,6 +55,7 @@ typedef struct BCM2835PeripheralState {
SDHCIState sdhci;
BCM2835SDHostState sdhost;
BCM2835GpioState gpio;
Bcm2835ThermalState thermal;
UnimplementedDeviceState i2s;
UnimplementedDeviceState spi[1];
UnimplementedDeviceState i2c[3];

View File

@ -35,7 +35,9 @@ typedef struct BCM283XState {
char *cpu_type;
uint32_t enabled_cpus;
ARMCPU cpus[BCM283X_NCPUS];
struct {
ARMCPU core;
} cpu[BCM283X_NCPUS];
BCM2836ControlState control;
BCM2835PeripheralState peripherals;
} BCM283XState;

View File

@ -48,6 +48,7 @@
#define SPI0_OFFSET 0x204000
#define BSC0_OFFSET 0x205000 /* BSC0 I2C/TWI */
#define OTP_OFFSET 0x20f000
#define THERMAL_OFFSET 0x212000
#define BSC_SL_OFFSET 0x214000 /* SPI slave */
#define AUX_OFFSET 0x215000 /* AUX: UART1/SPI1/SPI2 */
#define EMMC1_OFFSET 0x300000

View File

@ -0,0 +1,27 @@
/*
* BCM2835 dummy thermal sensor
*
* Copyright (C) 2019 Philippe Mathieu-Daudé <f4bug@amsat.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef HW_MISC_BCM2835_THERMAL_H
#define HW_MISC_BCM2835_THERMAL_H
#include "hw/sysbus.h"
#define TYPE_BCM2835_THERMAL "bcm2835-thermal"
#define BCM2835_THERMAL(obj) \
OBJECT_CHECK(Bcm2835ThermalState, (obj), TYPE_BCM2835_THERMAL)
typedef struct {
/*< private >*/
SysBusDevice parent_obj;
/*< public >*/
MemoryRegion iomem;
uint32_t ctl;
} Bcm2835ThermalState;
#endif

View File

@ -0,0 +1,33 @@
/*
* BCM2835 SYS timer emulation
*
* Copyright (c) 2019 Philippe Mathieu-Daudé <f4bug@amsat.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef BCM2835_SYSTIMER_H
#define BCM2835_SYSTIMER_H
#include "hw/sysbus.h"
#include "hw/irq.h"
#define TYPE_BCM2835_SYSTIMER "bcm2835-sys-timer"
#define BCM2835_SYSTIMER(obj) \
OBJECT_CHECK(BCM2835SystemTimerState, (obj), TYPE_BCM2835_SYSTIMER)
typedef struct {
/*< private >*/
SysBusDevice parent_obj;
/*< public >*/
MemoryRegion iomem;
qemu_irq irq;
struct {
uint32_t status;
uint32_t compare[4];
} reg;
} BCM2835SystemTimerState;
#endif

View File

@ -173,6 +173,7 @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
for (i = 1; i < 4; ++i) {
env->cp15.sctlr_el[i] |= SCTLR_EE;
}
arm_rebuild_hflags(env);
#endif
if (cpu_isar_feature(aa64_pauth, cpu)) {

View File

@ -440,6 +440,7 @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
} else {
env->cp15.sctlr_el[1] |= SCTLR_B;
}
arm_rebuild_hflags(env);
#endif
ts->stack_base = info->start_stack;

View File

@ -9984,6 +9984,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
aarch64_sve_narrow_vq(env, vq);
}
env->vfp.zcr_el[1] = vq - 1;
arm_rebuild_hflags(env);
ret = vq * 16;
}
return ret;

View File

@ -406,6 +406,7 @@ static void arm_cpu_reset(CPUState *s)
hw_breakpoint_update_all(cpu);
hw_watchpoint_update_all(cpu);
arm_rebuild_hflags(env);
}
bool arm_cpu_exec_interrupt(CPUState *cs, int interrupt_request)

View File

@ -231,6 +231,9 @@ typedef struct CPUARMState {
uint32_t pstate;
uint32_t aarch64; /* 1 if CPU is in aarch64 state; inverse of PSTATE.nRW */
/* Cached TBFLAGS state. See below for which bits are included. */
uint32_t hflags;
/* Frequently accessed CPSR bits are stored separately for efficiency.
This contains all the other bits. Use cpsr_{read,write} to access
the whole CPSR. */
@ -3105,33 +3108,44 @@ static inline uint64_t arm_sctlr(CPUARMState *env, int el)
}
}
static inline bool arm_cpu_data_is_big_endian_a32(CPUARMState *env,
bool sctlr_b)
{
#ifdef CONFIG_USER_ONLY
/*
* In system mode, BE32 is modelled in line with the
* architecture (as word-invariant big-endianness), where loads
* and stores are done little endian but from addresses which
* are adjusted by XORing with the appropriate constant. So the
* endianness to use for the raw data access is not affected by
* SCTLR.B.
* In user mode, however, we model BE32 as byte-invariant
* big-endianness (because user-only code cannot tell the
* difference), and so we need to use a data access endianness
* that depends on SCTLR.B.
*/
if (sctlr_b) {
return true;
}
#endif
/* In 32bit endianness is determined by looking at CPSR's E bit */
return env->uncached_cpsr & CPSR_E;
}
static inline bool arm_cpu_data_is_big_endian_a64(int el, uint64_t sctlr)
{
return sctlr & (el ? SCTLR_EE : SCTLR_E0E);
}
/* Return true if the processor is in big-endian mode. */
static inline bool arm_cpu_data_is_big_endian(CPUARMState *env)
{
/* In 32bit endianness is determined by looking at CPSR's E bit */
if (!is_a64(env)) {
return
#ifdef CONFIG_USER_ONLY
/* In system mode, BE32 is modelled in line with the
* architecture (as word-invariant big-endianness), where loads
* and stores are done little endian but from addresses which
* are adjusted by XORing with the appropriate constant. So the
* endianness to use for the raw data access is not affected by
* SCTLR.B.
* In user mode, however, we model BE32 as byte-invariant
* big-endianness (because user-only code cannot tell the
* difference), and so we need to use a data access endianness
* that depends on SCTLR.B.
*/
arm_sctlr_b(env) ||
#endif
((env->uncached_cpsr & CPSR_E) ? 1 : 0);
return arm_cpu_data_is_big_endian_a32(env, arm_sctlr_b(env));
} else {
int cur_el = arm_current_el(env);
uint64_t sctlr = arm_sctlr(env, cur_el);
return (sctlr & (cur_el ? SCTLR_EE : SCTLR_E0E)) != 0;
return arm_cpu_data_is_big_endian_a64(cur_el, sctlr);
}
}
@ -3140,15 +3154,18 @@ typedef ARMCPU ArchCPU;
#include "exec/cpu-all.h"
/* Bit usage in the TB flags field: bit 31 indicates whether we are
/*
* Bit usage in the TB flags field: bit 31 indicates whether we are
* in 32 or 64 bit mode. The meaning of the other bits depends on that.
* We put flags which are shared between 32 and 64 bit mode at the top
* of the word, and flags which apply to only one mode at the bottom.
*
* Unless otherwise noted, these bits are cached in env->hflags.
*/
FIELD(TBFLAG_ANY, AARCH64_STATE, 31, 1)
FIELD(TBFLAG_ANY, MMUIDX, 28, 3)
FIELD(TBFLAG_ANY, SS_ACTIVE, 27, 1)
FIELD(TBFLAG_ANY, PSTATE_SS, 26, 1)
FIELD(TBFLAG_ANY, PSTATE_SS, 26, 1) /* Not cached. */
/* Target EL if we take a floating-point-disabled exception */
FIELD(TBFLAG_ANY, FPEXC_EL, 24, 2)
FIELD(TBFLAG_ANY, BE_DATA, 23, 1)
@ -3159,13 +3176,14 @@ FIELD(TBFLAG_ANY, BE_DATA, 23, 1)
FIELD(TBFLAG_ANY, DEBUG_TARGET_EL, 21, 2)
/* Bit usage when in AArch32 state: */
FIELD(TBFLAG_A32, THUMB, 0, 1)
FIELD(TBFLAG_A32, VECLEN, 1, 3)
FIELD(TBFLAG_A32, VECSTRIDE, 4, 2)
FIELD(TBFLAG_A32, THUMB, 0, 1) /* Not cached. */
FIELD(TBFLAG_A32, VECLEN, 1, 3) /* Not cached. */
FIELD(TBFLAG_A32, VECSTRIDE, 4, 2) /* Not cached. */
/*
* We store the bottom two bits of the CPAR as TB flags and handle
* checks on the other bits at runtime. This shares the same bits as
* VECSTRIDE, which is OK as no XScale CPU has VFP.
* Not cached, because VECLEN+VECSTRIDE are not cached.
*/
FIELD(TBFLAG_A32, XSCALE_CPAR, 4, 2)
/*
@ -3174,15 +3192,15 @@ FIELD(TBFLAG_A32, XSCALE_CPAR, 4, 2)
* the same thing as the current security state of the processor!
*/
FIELD(TBFLAG_A32, NS, 6, 1)
FIELD(TBFLAG_A32, VFPEN, 7, 1)
FIELD(TBFLAG_A32, CONDEXEC, 8, 8)
FIELD(TBFLAG_A32, VFPEN, 7, 1) /* Partially cached, minus FPEXC. */
FIELD(TBFLAG_A32, CONDEXEC, 8, 8) /* Not cached. */
FIELD(TBFLAG_A32, SCTLR_B, 16, 1)
/* For M profile only, set if FPCCR.LSPACT is set */
FIELD(TBFLAG_A32, LSPACT, 18, 1)
FIELD(TBFLAG_A32, LSPACT, 18, 1) /* Not cached. */
/* For M profile only, set if we must create a new FP context */
FIELD(TBFLAG_A32, NEW_FP_CTXT_NEEDED, 19, 1)
FIELD(TBFLAG_A32, NEW_FP_CTXT_NEEDED, 19, 1) /* Not cached. */
/* For M profile only, set if FPCCR.S does not match current security state */
FIELD(TBFLAG_A32, FPCCR_S_WRONG, 20, 1)
FIELD(TBFLAG_A32, FPCCR_S_WRONG, 20, 1) /* Not cached. */
/* For M profile only, Handler (ie not Thread) mode */
FIELD(TBFLAG_A32, HANDLER, 21, 1)
/* For M profile only, whether we should generate stack-limit checks */
@ -3194,7 +3212,7 @@ FIELD(TBFLAG_A64, SVEEXC_EL, 2, 2)
FIELD(TBFLAG_A64, ZCR_LEN, 4, 4)
FIELD(TBFLAG_A64, PAUTH_ACTIVE, 8, 1)
FIELD(TBFLAG_A64, BT, 9, 1)
FIELD(TBFLAG_A64, BTYPE, 10, 2)
FIELD(TBFLAG_A64, BTYPE, 10, 2) /* Not cached. */
FIELD(TBFLAG_A64, TBID, 12, 2)
static inline bool bswap_code(bool sctlr_b)
@ -3279,6 +3297,12 @@ void arm_register_pre_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook,
void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook, void
*opaque);
/**
* arm_rebuild_hflags:
* Rebuild the cached TBFLAGS for arbitrary changed processor state.
*/
void arm_rebuild_hflags(CPUARMState *env);
/**
* aa32_vfp_dreg:
* Return a pointer to the Dn register within env in 32-bit mode.

View File

@ -1025,6 +1025,7 @@ void HELPER(exception_return)(CPUARMState *env, uint64_t new_pc)
} else {
env->regs[15] = new_pc & ~0x3;
}
helper_rebuild_hflags_a32(env, new_el);
qemu_log_mask(CPU_LOG_INT, "Exception return from AArch64 EL%d to "
"AArch32 EL%d PC 0x%" PRIx32 "\n",
cur_el, new_el, env->regs[15]);
@ -1036,10 +1037,12 @@ void HELPER(exception_return)(CPUARMState *env, uint64_t new_pc)
}
aarch64_restore_sp(env, new_el);
env->pc = new_pc;
helper_rebuild_hflags_a64(env, new_el);
qemu_log_mask(CPU_LOG_INT, "Exception return from AArch64 EL%d to "
"AArch64 EL%d PC 0x%" PRIx64 "\n",
cur_el, new_el, env->pc);
}
/*
* Note that cur_el can never be 0. If new_el is 0, then
* el0_a64 is return_to_aa64, else el0_a64 is ignored.

View File

@ -4174,6 +4174,16 @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri,
/* ??? Lots of these bits are not implemented. */
/* This may enable/disable the MMU, so do a TLB flush. */
tlb_flush(CPU(cpu));
if (ri->type & ARM_CP_SUPPRESS_TB_END) {
/*
* Normally we would always end the TB on an SCTLR write; see the
* comment in ARMCPRegInfo sctlr initialization below for why Xscale
* is special. Setting ARM_CP_SUPPRESS_TB_END also stops the rebuild
* of hflags from the translator, so do it here.
*/
arm_rebuild_hflags(env);
}
}
static CPAccessResult fpexc32_access(CPUARMState *env, const ARMCPRegInfo *ri,
@ -7998,6 +8008,7 @@ static void take_aarch32_exception(CPUARMState *env, int new_mode,
env->regs[14] = env->regs[15] + offset;
}
env->regs[15] = newpc;
arm_rebuild_hflags(env);
}
static void arm_cpu_do_interrupt_aarch32_hyp(CPUState *cs)
@ -8345,6 +8356,7 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
pstate_write(env, PSTATE_DAIF | new_mode);
env->aarch64 = 1;
aarch64_restore_sp(env, new_el);
helper_rebuild_hflags_a64(env, new_el);
env->pc = addr;
@ -11026,15 +11038,12 @@ ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate)
}
#endif
ARMMMUIdx arm_mmu_idx(CPUARMState *env)
ARMMMUIdx arm_mmu_idx_el(CPUARMState *env, int el)
{
int el;
if (arm_feature(env, ARM_FEATURE_M)) {
return arm_v7m_mmu_idx_for_secstate(env, env->v7m.secure);
}
el = arm_current_el(env);
if (el < 2 && arm_is_secure_below_el3(env)) {
return ARMMMUIdx_S1SE0 + el;
} else {
@ -11042,6 +11051,11 @@ ARMMMUIdx arm_mmu_idx(CPUARMState *env)
}
}
ARMMMUIdx arm_mmu_idx(CPUARMState *env)
{
return arm_mmu_idx_el(env, arm_current_el(env));
}
int cpu_mmu_index(CPUARMState *env, bool ifetch)
{
return arm_to_core_mmu_idx(arm_mmu_idx(env));
@ -11054,171 +11068,276 @@ ARMMMUIdx arm_stage1_mmu_idx(CPUARMState *env)
}
#endif
void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
target_ulong *cs_base, uint32_t *pflags)
static uint32_t rebuild_hflags_common(CPUARMState *env, int fp_el,
ARMMMUIdx mmu_idx, uint32_t flags)
{
ARMMMUIdx mmu_idx = arm_mmu_idx(env);
int current_el = arm_current_el(env);
int fp_el = fp_exception_el(env, current_el);
uint32_t flags = 0;
flags = FIELD_DP32(flags, TBFLAG_ANY, FPEXC_EL, fp_el);
flags = FIELD_DP32(flags, TBFLAG_ANY, MMUIDX,
arm_to_core_mmu_idx(mmu_idx));
if (is_a64(env)) {
ARMCPU *cpu = env_archcpu(env);
uint64_t sctlr;
*pc = env->pc;
flags = FIELD_DP32(flags, TBFLAG_ANY, AARCH64_STATE, 1);
/* Get control bits for tagged addresses. */
{
ARMMMUIdx stage1 = stage_1_mmu_idx(mmu_idx);
ARMVAParameters p0 = aa64_va_parameters_both(env, 0, stage1);
int tbii, tbid;
/* FIXME: ARMv8.1-VHE S2 translation regime. */
if (regime_el(env, stage1) < 2) {
ARMVAParameters p1 = aa64_va_parameters_both(env, -1, stage1);
tbid = (p1.tbi << 1) | p0.tbi;
tbii = tbid & ~((p1.tbid << 1) | p0.tbid);
} else {
tbid = p0.tbi;
tbii = tbid & !p0.tbid;
}
flags = FIELD_DP32(flags, TBFLAG_A64, TBII, tbii);
flags = FIELD_DP32(flags, TBFLAG_A64, TBID, tbid);
}
if (cpu_isar_feature(aa64_sve, cpu)) {
int sve_el = sve_exception_el(env, current_el);
uint32_t zcr_len;
/* If SVE is disabled, but FP is enabled,
* then the effective len is 0.
*/
if (sve_el != 0 && fp_el == 0) {
zcr_len = 0;
} else {
zcr_len = sve_zcr_len_for_el(env, current_el);
}
flags = FIELD_DP32(flags, TBFLAG_A64, SVEEXC_EL, sve_el);
flags = FIELD_DP32(flags, TBFLAG_A64, ZCR_LEN, zcr_len);
}
sctlr = arm_sctlr(env, current_el);
if (cpu_isar_feature(aa64_pauth, cpu)) {
/*
* In order to save space in flags, we record only whether
* pauth is "inactive", meaning all insns are implemented as
* a nop, or "active" when some action must be performed.
* The decision of which action to take is left to a helper.
*/
if (sctlr & (SCTLR_EnIA | SCTLR_EnIB | SCTLR_EnDA | SCTLR_EnDB)) {
flags = FIELD_DP32(flags, TBFLAG_A64, PAUTH_ACTIVE, 1);
}
}
if (cpu_isar_feature(aa64_bti, cpu)) {
/* Note that SCTLR_EL[23].BT == SCTLR_BT1. */
if (sctlr & (current_el == 0 ? SCTLR_BT0 : SCTLR_BT1)) {
flags = FIELD_DP32(flags, TBFLAG_A64, BT, 1);
}
flags = FIELD_DP32(flags, TBFLAG_A64, BTYPE, env->btype);
}
} else {
*pc = env->regs[15];
flags = FIELD_DP32(flags, TBFLAG_A32, THUMB, env->thumb);
flags = FIELD_DP32(flags, TBFLAG_A32, VECLEN, env->vfp.vec_len);
flags = FIELD_DP32(flags, TBFLAG_A32, VECSTRIDE, env->vfp.vec_stride);
flags = FIELD_DP32(flags, TBFLAG_A32, CONDEXEC, env->condexec_bits);
flags = FIELD_DP32(flags, TBFLAG_A32, SCTLR_B, arm_sctlr_b(env));
flags = FIELD_DP32(flags, TBFLAG_A32, NS, !access_secure_reg(env));
if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)
|| arm_el_is_aa64(env, 1) || arm_feature(env, ARM_FEATURE_M)) {
flags = FIELD_DP32(flags, TBFLAG_A32, VFPEN, 1);
}
/* Note that XSCALE_CPAR shares bits with VECSTRIDE */
if (arm_feature(env, ARM_FEATURE_XSCALE)) {
flags = FIELD_DP32(flags, TBFLAG_A32,
XSCALE_CPAR, env->cp15.c15_cpar);
}
}
flags = FIELD_DP32(flags, TBFLAG_ANY, MMUIDX, arm_to_core_mmu_idx(mmu_idx));
/* The SS_ACTIVE and PSTATE_SS bits correspond to the state machine
* states defined in the ARM ARM for software singlestep:
* SS_ACTIVE PSTATE.SS State
* 0 x Inactive (the TB flag for SS is always 0)
* 1 0 Active-pending
* 1 1 Active-not-pending
*/
if (arm_singlestep_active(env)) {
flags = FIELD_DP32(flags, TBFLAG_ANY, SS_ACTIVE, 1);
if (is_a64(env)) {
if (env->pstate & PSTATE_SS) {
flags = FIELD_DP32(flags, TBFLAG_ANY, PSTATE_SS, 1);
}
} else {
if (env->uncached_cpsr & PSTATE_SS) {
flags = FIELD_DP32(flags, TBFLAG_ANY, PSTATE_SS, 1);
}
}
}
if (arm_cpu_data_is_big_endian(env)) {
return flags;
}
static uint32_t rebuild_hflags_common_32(CPUARMState *env, int fp_el,
ARMMMUIdx mmu_idx, uint32_t flags)
{
bool sctlr_b = arm_sctlr_b(env);
if (sctlr_b) {
flags = FIELD_DP32(flags, TBFLAG_A32, SCTLR_B, 1);
}
if (arm_cpu_data_is_big_endian_a32(env, sctlr_b)) {
flags = FIELD_DP32(flags, TBFLAG_ANY, BE_DATA, 1);
}
flags = FIELD_DP32(flags, TBFLAG_ANY, FPEXC_EL, fp_el);
flags = FIELD_DP32(flags, TBFLAG_A32, NS, !access_secure_reg(env));
return rebuild_hflags_common(env, fp_el, mmu_idx, flags);
}
static uint32_t rebuild_hflags_m32(CPUARMState *env, int fp_el,
ARMMMUIdx mmu_idx)
{
uint32_t flags = 0;
/* v8M always enables the fpu. */
flags = FIELD_DP32(flags, TBFLAG_A32, VFPEN, 1);
if (arm_v7m_is_handler_mode(env)) {
flags = FIELD_DP32(flags, TBFLAG_A32, HANDLER, 1);
}
/* v8M always applies stack limit checks unless CCR.STKOFHFNMIGN is
* suppressing them because the requested execution priority is less than 0.
/*
* v8M always applies stack limit checks unless CCR.STKOFHFNMIGN
* is suppressing them because the requested execution priority
* is less than 0.
*/
if (arm_feature(env, ARM_FEATURE_V8) &&
arm_feature(env, ARM_FEATURE_M) &&
!((mmu_idx & ARM_MMU_IDX_M_NEGPRI) &&
!((mmu_idx & ARM_MMU_IDX_M_NEGPRI) &&
(env->v7m.ccr[env->v7m.secure] & R_V7M_CCR_STKOFHFNMIGN_MASK))) {
flags = FIELD_DP32(flags, TBFLAG_A32, STACKCHECK, 1);
}
if (arm_feature(env, ARM_FEATURE_M_SECURITY) &&
FIELD_EX32(env->v7m.fpccr[M_REG_S], V7M_FPCCR, S) != env->v7m.secure) {
flags = FIELD_DP32(flags, TBFLAG_A32, FPCCR_S_WRONG, 1);
return rebuild_hflags_common_32(env, fp_el, mmu_idx, flags);
}
static uint32_t rebuild_hflags_aprofile(CPUARMState *env)
{
int flags = 0;
flags = FIELD_DP32(flags, TBFLAG_ANY, DEBUG_TARGET_EL,
arm_debug_target_el(env));
return flags;
}
static uint32_t rebuild_hflags_a32(CPUARMState *env, int fp_el,
ARMMMUIdx mmu_idx)
{
uint32_t flags = rebuild_hflags_aprofile(env);
if (arm_el_is_aa64(env, 1)) {
flags = FIELD_DP32(flags, TBFLAG_A32, VFPEN, 1);
}
return rebuild_hflags_common_32(env, fp_el, mmu_idx, flags);
}
static uint32_t rebuild_hflags_a64(CPUARMState *env, int el, int fp_el,
ARMMMUIdx mmu_idx)
{
uint32_t flags = rebuild_hflags_aprofile(env);
ARMMMUIdx stage1 = stage_1_mmu_idx(mmu_idx);
ARMVAParameters p0 = aa64_va_parameters_both(env, 0, stage1);
uint64_t sctlr;
int tbii, tbid;
flags = FIELD_DP32(flags, TBFLAG_ANY, AARCH64_STATE, 1);
/* FIXME: ARMv8.1-VHE S2 translation regime. */
if (regime_el(env, stage1) < 2) {
ARMVAParameters p1 = aa64_va_parameters_both(env, -1, stage1);
tbid = (p1.tbi << 1) | p0.tbi;
tbii = tbid & ~((p1.tbid << 1) | p0.tbid);
} else {
tbid = p0.tbi;
tbii = tbid & !p0.tbid;
}
if (arm_feature(env, ARM_FEATURE_M) &&
(env->v7m.fpccr[env->v7m.secure] & R_V7M_FPCCR_ASPEN_MASK) &&
(!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK) ||
(env->v7m.secure &&
!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)))) {
flags = FIELD_DP32(flags, TBFLAG_A64, TBII, tbii);
flags = FIELD_DP32(flags, TBFLAG_A64, TBID, tbid);
if (cpu_isar_feature(aa64_sve, env_archcpu(env))) {
int sve_el = sve_exception_el(env, el);
uint32_t zcr_len;
/*
* ASPEN is set, but FPCA/SFPA indicate that there is no active
* FP context; we must create a new FP context before executing
* any FP insn.
* If SVE is disabled, but FP is enabled,
* then the effective len is 0.
*/
flags = FIELD_DP32(flags, TBFLAG_A32, NEW_FP_CTXT_NEEDED, 1);
if (sve_el != 0 && fp_el == 0) {
zcr_len = 0;
} else {
zcr_len = sve_zcr_len_for_el(env, el);
}
flags = FIELD_DP32(flags, TBFLAG_A64, SVEEXC_EL, sve_el);
flags = FIELD_DP32(flags, TBFLAG_A64, ZCR_LEN, zcr_len);
}
if (arm_feature(env, ARM_FEATURE_M)) {
bool is_secure = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
sctlr = arm_sctlr(env, el);
if (env->v7m.fpccr[is_secure] & R_V7M_FPCCR_LSPACT_MASK) {
flags = FIELD_DP32(flags, TBFLAG_A32, LSPACT, 1);
if (arm_cpu_data_is_big_endian_a64(el, sctlr)) {
flags = FIELD_DP32(flags, TBFLAG_ANY, BE_DATA, 1);
}
if (cpu_isar_feature(aa64_pauth, env_archcpu(env))) {
/*
* In order to save space in flags, we record only whether
* pauth is "inactive", meaning all insns are implemented as
* a nop, or "active" when some action must be performed.
* The decision of which action to take is left to a helper.
*/
if (sctlr & (SCTLR_EnIA | SCTLR_EnIB | SCTLR_EnDA | SCTLR_EnDB)) {
flags = FIELD_DP32(flags, TBFLAG_A64, PAUTH_ACTIVE, 1);
}
}
if (!arm_feature(env, ARM_FEATURE_M)) {
int target_el = arm_debug_target_el(env);
if (cpu_isar_feature(aa64_bti, env_archcpu(env))) {
/* Note that SCTLR_EL[23].BT == SCTLR_BT1. */
if (sctlr & (el == 0 ? SCTLR_BT0 : SCTLR_BT1)) {
flags = FIELD_DP32(flags, TBFLAG_A64, BT, 1);
}
}
flags = FIELD_DP32(flags, TBFLAG_ANY, DEBUG_TARGET_EL, target_el);
return rebuild_hflags_common(env, fp_el, mmu_idx, flags);
}
static uint32_t rebuild_hflags_internal(CPUARMState *env)
{
int el = arm_current_el(env);
int fp_el = fp_exception_el(env, el);
ARMMMUIdx mmu_idx = arm_mmu_idx_el(env, el);
if (is_a64(env)) {
return rebuild_hflags_a64(env, el, fp_el, mmu_idx);
} else if (arm_feature(env, ARM_FEATURE_M)) {
return rebuild_hflags_m32(env, fp_el, mmu_idx);
} else {
return rebuild_hflags_a32(env, fp_el, mmu_idx);
}
}
void arm_rebuild_hflags(CPUARMState *env)
{
env->hflags = rebuild_hflags_internal(env);
}
void HELPER(rebuild_hflags_m32)(CPUARMState *env, int el)
{
int fp_el = fp_exception_el(env, el);
ARMMMUIdx mmu_idx = arm_mmu_idx_el(env, el);
env->hflags = rebuild_hflags_m32(env, fp_el, mmu_idx);
}
void HELPER(rebuild_hflags_a32)(CPUARMState *env, int el)
{
int fp_el = fp_exception_el(env, el);
ARMMMUIdx mmu_idx = arm_mmu_idx_el(env, el);
env->hflags = rebuild_hflags_a32(env, fp_el, mmu_idx);
}
void HELPER(rebuild_hflags_a64)(CPUARMState *env, int el)
{
int fp_el = fp_exception_el(env, el);
ARMMMUIdx mmu_idx = arm_mmu_idx_el(env, el);
env->hflags = rebuild_hflags_a64(env, el, fp_el, mmu_idx);
}
void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
target_ulong *cs_base, uint32_t *pflags)
{
uint32_t flags = env->hflags;
uint32_t pstate_for_ss;
*cs_base = 0;
#ifdef CONFIG_DEBUG_TCG
assert(flags == rebuild_hflags_internal(env));
#endif
if (FIELD_EX32(flags, TBFLAG_ANY, AARCH64_STATE)) {
*pc = env->pc;
if (cpu_isar_feature(aa64_bti, env_archcpu(env))) {
flags = FIELD_DP32(flags, TBFLAG_A64, BTYPE, env->btype);
}
pstate_for_ss = env->pstate;
} else {
*pc = env->regs[15];
if (arm_feature(env, ARM_FEATURE_M)) {
if (arm_feature(env, ARM_FEATURE_M_SECURITY) &&
FIELD_EX32(env->v7m.fpccr[M_REG_S], V7M_FPCCR, S)
!= env->v7m.secure) {
flags = FIELD_DP32(flags, TBFLAG_A32, FPCCR_S_WRONG, 1);
}
if ((env->v7m.fpccr[env->v7m.secure] & R_V7M_FPCCR_ASPEN_MASK) &&
(!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK) ||
(env->v7m.secure &&
!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)))) {
/*
* ASPEN is set, but FPCA/SFPA indicate that there is no
* active FP context; we must create a new FP context before
* executing any FP insn.
*/
flags = FIELD_DP32(flags, TBFLAG_A32, NEW_FP_CTXT_NEEDED, 1);
}
bool is_secure = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
if (env->v7m.fpccr[is_secure] & R_V7M_FPCCR_LSPACT_MASK) {
flags = FIELD_DP32(flags, TBFLAG_A32, LSPACT, 1);
}
} else {
/*
* Note that XSCALE_CPAR shares bits with VECSTRIDE.
* Note that VECLEN+VECSTRIDE are RES0 for M-profile.
*/
if (arm_feature(env, ARM_FEATURE_XSCALE)) {
flags = FIELD_DP32(flags, TBFLAG_A32,
XSCALE_CPAR, env->cp15.c15_cpar);
} else {
flags = FIELD_DP32(flags, TBFLAG_A32, VECLEN,
env->vfp.vec_len);
flags = FIELD_DP32(flags, TBFLAG_A32, VECSTRIDE,
env->vfp.vec_stride);
}
if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) {
flags = FIELD_DP32(flags, TBFLAG_A32, VFPEN, 1);
}
}
flags = FIELD_DP32(flags, TBFLAG_A32, THUMB, env->thumb);
flags = FIELD_DP32(flags, TBFLAG_A32, CONDEXEC, env->condexec_bits);
pstate_for_ss = env->uncached_cpsr;
}
/*
* The SS_ACTIVE and PSTATE_SS bits correspond to the state machine
* states defined in the ARM ARM for software singlestep:
* SS_ACTIVE PSTATE.SS State
* 0 x Inactive (the TB flag for SS is always 0)
* 1 0 Active-pending
* 1 1 Active-not-pending
* SS_ACTIVE is set in hflags; PSTATE_SS is computed every TB.
*/
if (FIELD_EX32(flags, TBFLAG_ANY, SS_ACTIVE) &&
(pstate_for_ss & PSTATE_SS)) {
flags = FIELD_DP32(flags, TBFLAG_ANY, PSTATE_SS, 1);
}
*pflags = flags;
*cs_base = 0;
}
#ifdef TARGET_AARCH64

View File

@ -90,6 +90,10 @@ DEF_HELPER_4(msr_banked, void, env, i32, i32, i32)
DEF_HELPER_2(get_user_reg, i32, env, i32)
DEF_HELPER_3(set_user_reg, void, env, i32, i32)
DEF_HELPER_FLAGS_2(rebuild_hflags_m32, TCG_CALL_NO_RWG, void, env, int)
DEF_HELPER_FLAGS_2(rebuild_hflags_a32, TCG_CALL_NO_RWG, void, env, int)
DEF_HELPER_FLAGS_2(rebuild_hflags_a64, TCG_CALL_NO_RWG, void, env, int)
DEF_HELPER_1(vfp_get_fpscr, i32, env)
DEF_HELPER_2(vfp_set_fpscr, void, env, i32)

View File

@ -949,6 +949,15 @@ void arm_cpu_update_virq(ARMCPU *cpu);
*/
void arm_cpu_update_vfiq(ARMCPU *cpu);
/**
* arm_mmu_idx_el:
* @env: The cpu environment
* @el: The EL to use.
*
* Return the full ARMMMUIdx for the translation regime for EL.
*/
ARMMMUIdx arm_mmu_idx_el(CPUARMState *env, int el);
/**
* arm_mmu_idx:
* @env: The cpu environment

View File

@ -494,6 +494,7 @@ void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
switch_v7m_security_state(env, dest & 1);
env->thumb = 1;
env->regs[15] = dest & ~1;
arm_rebuild_hflags(env);
}
void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest)
@ -555,6 +556,7 @@ void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest)
switch_v7m_security_state(env, 0);
env->thumb = 1;
env->regs[15] = dest;
arm_rebuild_hflags(env);
}
static uint32_t *get_v7m_sp_ptr(CPUARMState *env, bool secure, bool threadmode,
@ -895,6 +897,7 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
env->regs[14] = lr;
env->regs[15] = addr & 0xfffffffe;
env->thumb = addr & 1;
arm_rebuild_hflags(env);
}
static void v7m_update_fpccr(CPUARMState *env, uint32_t frameptr,
@ -1765,6 +1768,7 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
/* Otherwise, we have a successful exception exit. */
arm_clear_exclusive(env);
arm_rebuild_hflags(env);
qemu_log_mask(CPU_LOG_INT, "...successful exception return\n");
}
@ -1837,6 +1841,7 @@ static bool do_v7m_function_return(ARMCPU *cpu)
xpsr_write(env, 0, XPSR_IT);
env->thumb = newpc & 1;
env->regs[15] = newpc & ~1;
arm_rebuild_hflags(env);
qemu_log_mask(CPU_LOG_INT, "...function return successful\n");
return true;
@ -1959,6 +1964,7 @@ static bool v7m_handle_execute_nsc(ARMCPU *cpu)
switch_v7m_security_state(env, true);
xpsr_write(env, 0, XPSR_IT);
env->regs[15] += 4;
arm_rebuild_hflags(env);
return true;
gen_invep:

View File

@ -756,6 +756,7 @@ static int cpu_post_load(void *opaque, int version_id)
if (!kvm_enabled()) {
pmu_op_finish(&cpu->env);
}
arm_rebuild_hflags(&cpu->env);
return 0;
}

View File

@ -224,6 +224,7 @@ uint32_t HELPER(usat16)(CPUARMState *env, uint32_t x, uint32_t shift)
void HELPER(setend)(CPUARMState *env)
{
env->uncached_cpsr ^= CPSR_E;
arm_rebuild_hflags(env);
}
/* Function checks whether WFx (WFI/WFE) instructions are set up to be trapped.
@ -387,6 +388,8 @@ uint32_t HELPER(cpsr_read)(CPUARMState *env)
void HELPER(cpsr_write)(CPUARMState *env, uint32_t val, uint32_t mask)
{
cpsr_write(env, val, mask, CPSRWriteByInstr);
/* TODO: Not all cpsr bits are relevant to hflags. */
arm_rebuild_hflags(env);
}
/* Write the CPSR for a 32-bit exception return */
@ -404,6 +407,7 @@ void HELPER(cpsr_write_eret)(CPUARMState *env, uint32_t val)
* state. Do the masking now.
*/
env->regs[15] &= (env->thumb ? ~1 : ~3);
arm_rebuild_hflags(env);
qemu_mutex_lock_iothread();
arm_call_el_change_hook(env_archcpu(env));

View File

@ -1789,8 +1789,17 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
if ((tb_cflags(s->base.tb) & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
/* I/O operations must end the TB here (whether read or write) */
s->base.is_jmp = DISAS_UPDATE;
} else if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) {
/* We default to ending the TB on a coprocessor register write,
}
if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) {
/*
* A write to any coprocessor regiser that ends a TB
* must rebuild the hflags for the next TB.
*/
TCGv_i32 tcg_el = tcg_const_i32(s->current_el);
gen_helper_rebuild_hflags_a64(cpu_env, tcg_el);
tcg_temp_free_i32(tcg_el);
/*
* We default to ending the TB on a coprocessor register write,
* but allow this to be suppressed by the register definition
* (usually only necessary to work around guest bugs).
*/

View File

@ -6890,6 +6890,8 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
ri = get_arm_cp_reginfo(s->cp_regs,
ENCODE_CP_REG(cpnum, is64, s->ns, crn, crm, opc1, opc2));
if (ri) {
bool need_exit_tb;
/* Check access permissions */
if (!cp_access_ok(s->current_el, ri, isread)) {
return 1;
@ -7068,14 +7070,30 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
}
}
if ((tb_cflags(s->base.tb) & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
/* I/O operations must end the TB here (whether read or write) */
gen_lookup_tb(s);
} else if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) {
/* We default to ending the TB on a coprocessor register write,
/* I/O operations must end the TB here (whether read or write) */
need_exit_tb = ((tb_cflags(s->base.tb) & CF_USE_ICOUNT) &&
(ri->type & ARM_CP_IO));
if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) {
/*
* A write to any coprocessor regiser that ends a TB
* must rebuild the hflags for the next TB.
*/
TCGv_i32 tcg_el = tcg_const_i32(s->current_el);
if (arm_dc_feature(s, ARM_FEATURE_M)) {
gen_helper_rebuild_hflags_m32(cpu_env, tcg_el);
} else {
gen_helper_rebuild_hflags_a32(cpu_env, tcg_el);
}
tcg_temp_free_i32(tcg_el);
/*
* We default to ending the TB on a coprocessor register write,
* but allow this to be suppressed by the register definition
* (usually only necessary to work around guest bugs).
*/
need_exit_tb = true;
}
if (need_exit_tb) {
gen_lookup_tb(s);
}
@ -8309,7 +8327,7 @@ static bool trans_MRS_v7m(DisasContext *s, arg_MRS_v7m *a)
static bool trans_MSR_v7m(DisasContext *s, arg_MSR_v7m *a)
{
TCGv_i32 addr, reg;
TCGv_i32 addr, reg, el;
if (!arm_dc_feature(s, ARM_FEATURE_M)) {
return false;
@ -8319,6 +8337,9 @@ static bool trans_MSR_v7m(DisasContext *s, arg_MSR_v7m *a)
gen_helper_v7m_msr(cpu_env, addr, reg);
tcg_temp_free_i32(addr);
tcg_temp_free_i32(reg);
el = tcg_const_i32(s->current_el);
gen_helper_rebuild_hflags_m32(cpu_env, el);
tcg_temp_free_i32(el);
gen_lookup_tb(s);
return true;
}