target-arm queue:

* various minor M profile bugfixes
  * aspeed/smc: handle dummy bytes when doing fast reads in command mode
  * pflash_cfi01: fix per-device sector length in CFI table
  * arm: stellaris: make MII accesses complete immediately
  * hw/char/exynos4210_uart: Drop unused local variable frame_size
  * arm_gicv3: Fix broken logic in ELRSR calculation
  * dma: omap: check dma channel data_type
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABCAAGBQJYi2djAAoJEDwlJe0UNgzey7gQAJiOTv78+bIKRlrHtY0Iklq4
 LaubD7ySIhy0/loN4p4adkIrPvGCozRLJ90TALULEWIY6zaefRwyH1NUkr+Zsqgk
 FZuDjopE2oQ7uZ4Xms4DjwsSfYbQuOReLynqJaaCI+qcatIcQI2Pff53SM7OHkKc
 dpw2suGrB2PKB9MZNslmclWvIwxCvLek78q7yc0kYMf3XXLHrXU/NyDnMSNKSRak
 JlsLvZb2ma5itSSgSRXafoLIX5Tr9R837P5pTs8asEhVBXkRUX31UCsub18A/X11
 UwtnLejosK9ohQB7PX9zTRPAzPk7OABvb2HW6+wax2UJg63lgYHcm0Trp6l3U1+J
 p4k5eJrrk5fdg+WR1vDWUezKMgqV/CN7libYc5rH7d9AXzzDLh+EuEhrH2LsS73M
 uXGaMPhORFPravvCq95BNmEnkl6w7CgyyHLMf31cvmDJAbQKdAW+LL8aGL5G5Fm0
 QbZOihw6ycfHPgmdytEX57aLxJ8y6Hr0AQJ3DO1NS0+y/mipTmdbvF/OH6NS1z8v
 /IIXZpV+8BKfupxlVEnaaGxJ+QnH8JP4CrrjKcHDhq6CffdYzIF/Vnmq0Mc6Qx97
 qT/cvWJ2cR/GgSDohdhmDvElHxo5q0DnjOU+fORxaSvf1wY9NdaAp8DDdDxy8pOH
 DzaMGajgtb2l3FfX21zp
 =0R2j
 -----END PGP SIGNATURE-----

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

target-arm queue:
 * various minor M profile bugfixes
 * aspeed/smc: handle dummy bytes when doing fast reads in command mode
 * pflash_cfi01: fix per-device sector length in CFI table
 * arm: stellaris: make MII accesses complete immediately
 * hw/char/exynos4210_uart: Drop unused local variable frame_size
 * arm_gicv3: Fix broken logic in ELRSR calculation
 * dma: omap: check dma channel data_type

# gpg: Signature made Fri 27 Jan 2017 15:29:39 GMT
# gpg:                using RSA key 0x3C2525ED14360CDE
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>"
# gpg:                 aka "Peter Maydell <pmaydell@gmail.com>"
# gpg:                 aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>"
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83  15CF 3C25 25ED 1436 0CDE

* remotes/pmaydell/tags/pull-target-arm-20170127: (22 commits)
  dma: omap: check dma channel data_type
  arm_gicv3: Fix broken logic in ELRSR calculation
  hw/char/exynos4210_uart: Drop unused local variable frame_size
  arm: stellaris: make MII accesses complete immediately
  armv7m: R14 should reset to 0xffffffff
  armv7m: FAULTMASK should be 0 on reset
  armv7m: Honour CCR.USERSETMPEND
  armv7m: Report no-coprocessor faults correctly
  armv7m: set CFSR.UNDEFINSTR on undefined instructions
  armv7m: honour CCR.STACKALIGN on exception entry
  armv7m: implement CCR, CFSR, HFSR, DFSR, BFAR, and MMFAR
  armv7m: add state for v7M CCR, CFSR, HFSR, DFSR, MMFAR, BFAR
  armv7m_nvic: keep a pointer to the CPU
  target/arm: Drop IS_M() macro
  pflash_cfi01: fix per-device sector length in CFI table
  armv7m: Clear FAULTMASK on return from non-NMI exceptions
  armv7m: Fix reads of CONTROL register bit 1
  hw/registerfields.h: Pull FIELD etc macros out of hw/register.h
  armv7m: Explicit error for bad vector table
  armv7m: Replace armv7m.hack with unassigned_access handler
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
master
Peter Maydell 2017-01-27 16:59:17 +00:00
commit 3aca12f841
18 changed files with 386 additions and 169 deletions

View File

@ -180,7 +180,6 @@ DeviceState *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq,
uint64_t entry;
uint64_t lowaddr;
int big_endian;
MemoryRegion *hack = g_new(MemoryRegion, 1);
if (cpu_model == NULL) {
cpu_model = "cortex-m3";
@ -225,13 +224,6 @@ DeviceState *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq,
}
}
/* Hack to map an additional page of ram at the top of the address
space. This stops qemu complaining about executing code outside RAM
when returning from an exception. */
memory_region_init_ram(hack, NULL, "armv7m.hack", 0x1000, &error_fatal);
vmstate_register_ram_global(hack);
memory_region_add_subregion(system_memory, 0xfffff000, hack);
qemu_register_reset(armv7m_reset, cpu);
return nvic;
}

View File

@ -99,6 +99,7 @@ struct pflash_t {
char *name;
void *storage;
VMChangeStateEntry *vmstate;
bool old_multiple_chip_handling;
};
static int pflash_post_load(void *opaque, int version_id);
@ -703,7 +704,7 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
pflash_t *pfl = CFI_PFLASH01(dev);
uint64_t total_len;
int ret;
uint64_t blocks_per_device, device_len;
uint64_t blocks_per_device, sector_len_per_device, device_len;
int num_devices;
Error *local_err = NULL;
@ -726,8 +727,14 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
* in the cfi_table[].
*/
num_devices = pfl->device_width ? (pfl->bank_width / pfl->device_width) : 1;
blocks_per_device = pfl->nb_blocs / num_devices;
device_len = pfl->sector_len * blocks_per_device;
if (pfl->old_multiple_chip_handling) {
blocks_per_device = pfl->nb_blocs / num_devices;
sector_len_per_device = pfl->sector_len;
} else {
blocks_per_device = pfl->nb_blocs;
sector_len_per_device = pfl->sector_len / num_devices;
}
device_len = sector_len_per_device * blocks_per_device;
/* XXX: to be fixed */
#if 0
@ -832,6 +839,9 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
pfl->cfi_table[0x2A] = 0x0B;
}
pfl->writeblock_size = 1 << pfl->cfi_table[0x2A];
if (!pfl->old_multiple_chip_handling && num_devices > 1) {
pfl->writeblock_size *= num_devices;
}
pfl->cfi_table[0x2B] = 0x00;
/* Number of erase block regions (uniform) */
@ -839,8 +849,8 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
/* Erase block region 1 */
pfl->cfi_table[0x2D] = blocks_per_device - 1;
pfl->cfi_table[0x2E] = (blocks_per_device - 1) >> 8;
pfl->cfi_table[0x2F] = pfl->sector_len >> 8;
pfl->cfi_table[0x30] = pfl->sector_len >> 16;
pfl->cfi_table[0x2F] = sector_len_per_device >> 8;
pfl->cfi_table[0x30] = sector_len_per_device >> 16;
/* Extended */
pfl->cfi_table[0x31] = 'P';
@ -898,6 +908,8 @@ static Property pflash_cfi01_properties[] = {
DEFINE_PROP_UINT16("id2", struct pflash_t, ident2, 0),
DEFINE_PROP_UINT16("id3", struct pflash_t, ident3, 0),
DEFINE_PROP_STRING("name", struct pflash_t, name),
DEFINE_PROP_BOOL("old-multiple-chip-handling", struct pflash_t,
old_multiple_chip_handling, false),
DEFINE_PROP_END_OF_LIST(),
};

View File

@ -306,7 +306,7 @@ static void exynos4210_uart_update_irq(Exynos4210UartState *s)
static void exynos4210_uart_update_parameters(Exynos4210UartState *s)
{
int speed, parity, data_bits, stop_bits, frame_size;
int speed, parity, data_bits, stop_bits;
QEMUSerialSetParams ssp;
uint64_t uclk_rate;
@ -314,9 +314,7 @@ static void exynos4210_uart_update_parameters(Exynos4210UartState *s)
return;
}
frame_size = 1; /* start bit */
if (s->reg[I_(ULCON)] & 0x20) {
frame_size++; /* parity bit */
if (s->reg[I_(ULCON)] & 0x28) {
parity = 'E';
} else {
@ -334,8 +332,6 @@ static void exynos4210_uart_update_parameters(Exynos4210UartState *s)
data_bits = (s->reg[I_(ULCON)] & 0x3) + 5;
frame_size += data_bits + stop_bits;
uclk_rate = 24000000;
speed = uclk_rate / ((16 * (s->reg[I_(UBRDIV)]) & 0xffff) +

View File

@ -878,15 +878,17 @@ static int omap_dma_ch_reg_write(struct omap_dma_s *s,
ch->burst[0] = (value & 0x0180) >> 7;
ch->pack[0] = (value & 0x0040) >> 6;
ch->port[0] = (enum omap_dma_port) ((value & 0x003c) >> 2);
ch->data_type = 1 << (value & 3);
if (ch->port[0] >= __omap_dma_port_last)
printf("%s: invalid DMA port %i\n", __FUNCTION__,
ch->port[0]);
if (ch->port[1] >= __omap_dma_port_last)
printf("%s: invalid DMA port %i\n", __FUNCTION__,
ch->port[1]);
if ((value & 3) == 3)
ch->data_type = 1 << (value & 3);
if ((value & 3) == 3) {
printf("%s: bad data_type for DMA channel\n", __FUNCTION__);
ch->data_type >>= 1;
}
break;
case 0x02: /* SYS_DMA_CCR_CH0 */
@ -1988,8 +1990,10 @@ static void omap_dma4_write(void *opaque, hwaddr addr,
fprintf(stderr, "%s: bad MReqAddressTranslate sideband signal\n",
__FUNCTION__);
ch->data_type = 1 << (value & 3);
if ((value & 3) == 3)
if ((value & 3) == 3) {
printf("%s: bad data_type for DMA channel\n", __FUNCTION__);
ch->data_type >>= 1;
}
break;
case 0x14: /* DMA4_CEN */

View File

@ -2430,7 +2430,7 @@ static uint64_t ich_elrsr_read(CPUARMState *env, const ARMCPRegInfo *ri)
uint64_t lr = cs->ich_lr_el2[i];
if ((lr & ICH_LR_EL2_STATE_MASK) == 0 &&
((lr & ICH_LR_EL2_HW) == 1 || (lr & ICH_LR_EL2_EOI) == 0)) {
((lr & ICH_LR_EL2_HW) != 0 || (lr & ICH_LR_EL2_EOI) == 0)) {
value |= (1 << i);
}
}

View File

@ -23,6 +23,7 @@
typedef struct {
GICState gic;
ARMCPU *cpu;
struct {
uint32_t control;
uint32_t reload;
@ -155,7 +156,7 @@ void armv7m_nvic_complete_irq(void *opaque, int irq)
static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
{
ARMCPU *cpu;
ARMCPU *cpu = s->cpu;
uint32_t val;
int irq;
@ -187,11 +188,9 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
case 0x1c: /* SysTick Calibration Value. */
return 10000;
case 0xd00: /* CPUID Base. */
cpu = ARM_CPU(qemu_get_cpu(0));
return cpu->midr;
case 0xd04: /* Interrupt Control State. */
/* VECTACTIVE */
cpu = ARM_CPU(qemu_get_cpu(0));
val = cpu->env.v7m.exception;
if (val == 1023) {
val = 0;
@ -222,7 +221,6 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
val |= (1 << 31);
return val;
case 0xd08: /* Vector Table Offset. */
cpu = ARM_CPU(qemu_get_cpu(0));
return cpu->env.v7m.vecbase;
case 0xd0c: /* Application Interrupt/Reset Control. */
return 0xfa050000;
@ -230,8 +228,7 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
/* TODO: Implement SLEEPONEXIT. */
return 0;
case 0xd14: /* Configuration Control. */
/* TODO: Implement Configuration Control bits. */
return 0;
return cpu->env.v7m.ccr;
case 0xd24: /* System Handler Status. */
val = 0;
if (s->gic.irq_state[ARMV7M_EXCP_MEM].active) val |= (1 << 0);
@ -250,16 +247,19 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
if (s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled) val |= (1 << 18);
return val;
case 0xd28: /* Configurable Fault Status. */
/* TODO: Implement Fault Status. */
qemu_log_mask(LOG_UNIMP, "Configurable Fault Status unimplemented\n");
return 0;
return cpu->env.v7m.cfsr;
case 0xd2c: /* Hard Fault Status. */
return cpu->env.v7m.hfsr;
case 0xd30: /* Debug Fault Status. */
case 0xd34: /* Mem Manage Address. */
return cpu->env.v7m.dfsr;
case 0xd34: /* MMFAR MemManage Fault Address */
return cpu->env.v7m.mmfar;
case 0xd38: /* Bus Fault Address. */
return cpu->env.v7m.bfar;
case 0xd3c: /* Aux Fault Status. */
/* TODO: Implement fault status registers. */
qemu_log_mask(LOG_UNIMP, "Fault status registers unimplemented\n");
qemu_log_mask(LOG_UNIMP,
"Aux Fault status registers unimplemented\n");
return 0;
case 0xd40: /* PFR0. */
return 0x00000030;
@ -296,7 +296,7 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value)
{
ARMCPU *cpu;
ARMCPU *cpu = s->cpu;
uint32_t oldval;
switch (offset) {
case 0x10: /* SysTick Control and Status. */
@ -349,7 +349,6 @@ static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value)
}
break;
case 0xd08: /* Vector Table Offset. */
cpu = ARM_CPU(qemu_get_cpu(0));
cpu->env.v7m.vecbase = value & 0xffffff80;
break;
case 0xd0c: /* Application Interrupt/Reset Control. */
@ -369,9 +368,19 @@ static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value)
}
break;
case 0xd10: /* System Control. */
case 0xd14: /* Configuration Control. */
/* TODO: Implement control registers. */
qemu_log_mask(LOG_UNIMP, "NVIC: SCR and CCR unimplemented\n");
qemu_log_mask(LOG_UNIMP, "NVIC: SCR unimplemented\n");
break;
case 0xd14: /* Configuration Control. */
/* Enforce RAZ/WI on reserved and must-RAZ/WI bits */
value &= (R_V7M_CCR_STKALIGN_MASK |
R_V7M_CCR_BFHFNMIGN_MASK |
R_V7M_CCR_DIV_0_TRP_MASK |
R_V7M_CCR_UNALIGN_TRP_MASK |
R_V7M_CCR_USERSETMPEND_MASK |
R_V7M_CCR_NONBASETHRDENA_MASK);
cpu->env.v7m.ccr = value;
break;
case 0xd24: /* System Handler Control. */
/* TODO: Real hardware allows you to set/clear the active bits
@ -381,16 +390,29 @@ static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value)
s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled = (value & (1 << 18)) != 0;
break;
case 0xd28: /* Configurable Fault Status. */
cpu->env.v7m.cfsr &= ~value; /* W1C */
break;
case 0xd2c: /* Hard Fault Status. */
cpu->env.v7m.hfsr &= ~value; /* W1C */
break;
case 0xd30: /* Debug Fault Status. */
cpu->env.v7m.dfsr &= ~value; /* W1C */
break;
case 0xd34: /* Mem Manage Address. */
cpu->env.v7m.mmfar = value;
return;
case 0xd38: /* Bus Fault Address. */
cpu->env.v7m.bfar = value;
return;
case 0xd3c: /* Aux Fault Status. */
qemu_log_mask(LOG_UNIMP,
"NVIC: fault status registers unimplemented\n");
"NVIC: Aux fault status registers unimplemented\n");
break;
case 0xf00: /* Software Triggered Interrupt Register */
if ((value & 0x1ff) < s->num_irq) {
/* user mode can only write to STIR if CCR.USERSETMPEND permits it */
if ((value & 0x1ff) < s->num_irq &&
(arm_current_el(&cpu->env) ||
(cpu->env.v7m.ccr & R_V7M_CCR_USERSETMPEND_MASK))) {
gic_set_pending_private(&s->gic, 0, value & 0x1ff);
}
break;
@ -495,6 +517,8 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp)
NVICClass *nc = NVIC_GET_CLASS(s);
Error *local_err = NULL;
s->cpu = ARM_CPU(qemu_get_cpu(0));
assert(s->cpu);
/* The NVIC always has only one CPU */
s->gic.num_cpu = 1;
/* Tell the common code we're an NVIC */

View File

@ -416,7 +416,10 @@ static void stellaris_enet_write(void *opaque, hwaddr offset,
s->thr = value;
break;
case 0x20: /* MCTL */
s->mctl = value;
/* TODO: MII registers aren't modelled.
* Clear START, indicating that the operation completes immediately.
*/
s->mctl = value & ~1;
break;
case 0x24: /* MDV */
s->mdv = value;

View File

@ -69,7 +69,9 @@
#define R_CTRL0 (0x10 / 4)
#define CTRL_CMD_SHIFT 16
#define CTRL_CMD_MASK 0xff
#define CTRL_DUMMY_HIGH_SHIFT 14
#define CTRL_AST2400_SPI_4BYTE (1 << 13)
#define CTRL_DUMMY_LOW_SHIFT 6 /* 2 bits [7:6] */
#define CTRL_CE_STOP_ACTIVE (1 << 2)
#define CTRL_CMD_MODE_MASK 0x3
#define CTRL_READMODE 0x0
@ -485,6 +487,16 @@ static uint32_t aspeed_smc_check_segment_addr(const AspeedSMCFlash *fl,
return addr;
}
static int aspeed_smc_flash_dummies(const AspeedSMCFlash *fl)
{
const AspeedSMCState *s = fl->controller;
uint32_t r_ctrl0 = s->regs[s->r_ctrl0 + fl->id];
uint32_t dummy_high = (r_ctrl0 >> CTRL_DUMMY_HIGH_SHIFT) & 0x1;
uint32_t dummy_low = (r_ctrl0 >> CTRL_DUMMY_LOW_SHIFT) & 0x3;
return ((dummy_high << 2) | dummy_low) * 8;
}
static void aspeed_smc_flash_send_addr(AspeedSMCFlash *fl, uint32_t addr)
{
const AspeedSMCState *s = fl->controller;
@ -521,6 +533,15 @@ static uint64_t aspeed_smc_flash_read(void *opaque, hwaddr addr, unsigned size)
aspeed_smc_flash_select(fl);
aspeed_smc_flash_send_addr(fl, addr);
/*
* Use fake transfers to model dummy bytes. The value should
* be configured to some non-zero value in fast read mode and
* zero in read mode.
*/
for (i = 0; i < aspeed_smc_flash_dummies(fl); i++) {
ssi_transfer(fl->controller->spi, 0xFF);
}
for (i = 0; i < size; i++) {
ret |= ssi_transfer(s->spi, 0x0) << (8 * i);
}

View File

@ -10,6 +10,10 @@
.driver = "fw_cfg_io",\
.property = "x-file-slots",\
.value = stringify(0x10),\
},{\
.driver = "pflash_cfi01",\
.property = "old-multiple-chip-handling",\
.value = "on",\
},
#define HW_COMPAT_2_7 \

View File

@ -13,6 +13,7 @@
#include "hw/qdev-core.h"
#include "exec/memory.h"
#include "hw/registerfields.h"
typedef struct RegisterInfo RegisterInfo;
typedef struct RegisterAccessInfo RegisterAccessInfo;
@ -206,50 +207,4 @@ RegisterInfoArray *register_init_block32(DeviceState *owner,
void register_finalize_block(RegisterInfoArray *r_array);
/* Define constants for a 32 bit register */
/* This macro will define A_FOO, for the byte address of a register
* as well as R_FOO for the uint32_t[] register number (A_FOO / 4).
*/
#define REG32(reg, addr) \
enum { A_ ## reg = (addr) }; \
enum { R_ ## reg = (addr) / 4 };
/* Define SHIFT, LENGTH and MASK constants for a field within a register */
/* This macro will define FOO_BAR_MASK, FOO_BAR_SHIFT and FOO_BAR_LENGTH
* constants for field BAR in register FOO.
*/
#define FIELD(reg, field, shift, length) \
enum { R_ ## reg ## _ ## field ## _SHIFT = (shift)}; \
enum { R_ ## reg ## _ ## field ## _LENGTH = (length)}; \
enum { R_ ## reg ## _ ## field ## _MASK = \
MAKE_64BIT_MASK(shift, length)};
/* Extract a field from a register */
#define FIELD_EX32(storage, reg, field) \
extract32((storage), R_ ## reg ## _ ## field ## _SHIFT, \
R_ ## reg ## _ ## field ## _LENGTH)
/* Extract a field from an array of registers */
#define ARRAY_FIELD_EX32(regs, reg, field) \
FIELD_EX32((regs)[R_ ## reg], reg, field)
/* Deposit a register field.
* Assigning values larger then the target field will result in
* compilation warnings.
*/
#define FIELD_DP32(storage, reg, field, val) ({ \
struct { \
unsigned int v:R_ ## reg ## _ ## field ## _LENGTH; \
} v = { .v = val }; \
uint32_t d; \
d = deposit32((storage), R_ ## reg ## _ ## field ## _SHIFT, \
R_ ## reg ## _ ## field ## _LENGTH, v.v); \
d; })
/* Deposit a field to array of registers. */
#define ARRAY_FIELD_DP32(regs, reg, field, val) \
(regs)[R_ ## reg] = FIELD_DP32((regs)[R_ ## reg], reg, field, val);
#endif

View File

@ -0,0 +1,60 @@
/*
* Register Definition API: field macros
*
* Copyright (c) 2016 Xilinx Inc.
* Copyright (c) 2013 Peter Crosthwaite <peter.crosthwaite@xilinx.com>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*/
#ifndef REGISTERFIELDS_H
#define REGISTERFIELDS_H
/* Define constants for a 32 bit register */
/* This macro will define A_FOO, for the byte address of a register
* as well as R_FOO for the uint32_t[] register number (A_FOO / 4).
*/
#define REG32(reg, addr) \
enum { A_ ## reg = (addr) }; \
enum { R_ ## reg = (addr) / 4 };
/* Define SHIFT, LENGTH and MASK constants for a field within a register */
/* This macro will define FOO_BAR_MASK, FOO_BAR_SHIFT and FOO_BAR_LENGTH
* constants for field BAR in register FOO.
*/
#define FIELD(reg, field, shift, length) \
enum { R_ ## reg ## _ ## field ## _SHIFT = (shift)}; \
enum { R_ ## reg ## _ ## field ## _LENGTH = (length)}; \
enum { R_ ## reg ## _ ## field ## _MASK = \
MAKE_64BIT_MASK(shift, length)};
/* Extract a field from a register */
#define FIELD_EX32(storage, reg, field) \
extract32((storage), R_ ## reg ## _ ## field ## _SHIFT, \
R_ ## reg ## _ ## field ## _LENGTH)
/* Extract a field from an array of registers */
#define ARRAY_FIELD_EX32(regs, reg, field) \
FIELD_EX32((regs)[R_ ## reg], reg, field)
/* Deposit a register field.
* Assigning values larger then the target field will result in
* compilation warnings.
*/
#define FIELD_DP32(storage, reg, field, val) ({ \
struct { \
unsigned int v:R_ ## reg ## _ ## field ## _LENGTH; \
} v = { .v = val }; \
uint32_t d; \
d = deposit32((storage), R_ ## reg ## _ ## field ## _SHIFT, \
R_ ## reg ## _ ## field ## _LENGTH, v.v); \
d; })
/* Deposit a field to array of registers. */
#define ARRAY_FIELD_DP32(regs, reg, field, val) \
(regs)[R_ ## reg] = FIELD_DP32((regs)[R_ ## reg], reg, field, val);
#endif

View File

@ -573,6 +573,7 @@ void cpu_loop(CPUARMState *env)
switch(trapnr) {
case EXCP_UDEF:
case EXCP_NOCP:
{
TaskState *ts = cs->opaque;
uint32_t opcode;

View File

@ -179,15 +179,27 @@ static void arm_cpu_reset(CPUState *s)
/* SVC mode with interrupts disabled. */
env->uncached_cpsr = ARM_CPU_MODE_SVC;
env->daif = PSTATE_D | PSTATE_A | PSTATE_I | PSTATE_F;
/* On ARMv7-M the CPSR_I is the value of the PRIMASK register, and is
* clear at reset. Initial SP and PC are loaded from ROM.
*/
if (IS_M(env)) {
if (arm_feature(env, ARM_FEATURE_M)) {
uint32_t initial_msp; /* Loaded from 0x0 */
uint32_t initial_pc; /* Loaded from 0x4 */
uint8_t *rom;
env->daif &= ~PSTATE_I;
/* For M profile we store FAULTMASK and PRIMASK in the
* PSTATE F and I bits; these are both clear at reset.
*/
env->daif &= ~(PSTATE_I | PSTATE_F);
/* The reset value of this bit is IMPDEF, but ARM recommends
* that it resets to 1, so QEMU always does that rather than making
* it dependent on CPU model.
*/
env->v7m.ccr = R_V7M_CCR_STKALIGN_MASK;
/* Unlike A/R profile, M profile defines the reset LR value */
env->regs[14] = 0xffffffff;
/* Load the initial SP and PC from the vector table at address 0 */
rom = rom_ptr(0);
if (rom) {
/* Address zero is covered by ROM which hasn't yet been
@ -292,6 +304,33 @@ bool arm_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
}
#if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64)
static void arm_v7m_unassigned_access(CPUState *cpu, hwaddr addr,
bool is_write, bool is_exec, int opaque,
unsigned size)
{
ARMCPU *arm = ARM_CPU(cpu);
CPUARMState *env = &arm->env;
/* ARMv7-M interrupt return works by loading a magic value into the PC.
* On real hardware the load causes the return to occur. The qemu
* implementation performs the jump normally, then does the exception
* return by throwing a special exception when when the CPU tries to
* execute code at the magic address.
*/
if (env->v7m.exception != 0 && addr >= 0xfffffff0 && is_exec) {
cpu->exception_index = EXCP_EXCEPTION_EXIT;
cpu_loop_exit(cpu);
}
/* In real hardware an attempt to access parts of the address space
* with nothing there will usually cause an external abort.
* However our QEMU board models are often missing device models where
* the guest can boot anyway with the default read-as-zero/writes-ignored
* behaviour that you get without a QEMU unassigned_access hook.
* So just return here to retain that default behaviour.
*/
}
static bool arm_v7m_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
{
CPUClass *cc = CPU_GET_CLASS(cs);
@ -1016,6 +1055,7 @@ static void arm_v7m_class_init(ObjectClass *oc, void *data)
cc->do_interrupt = arm_v7m_cpu_do_interrupt;
#endif
cc->do_unassigned_access = arm_v7m_unassigned_access;
cc->cpu_exec_interrupt = arm_v7m_cpu_exec_interrupt;
}

View File

@ -21,6 +21,7 @@
#define ARM_CPU_H
#include "kvm-consts.h"
#include "hw/registerfields.h"
#if defined(TARGET_AARCH64)
/* AArch64 definitions */
@ -52,6 +53,7 @@
#define EXCP_VIRQ 14
#define EXCP_VFIQ 15
#define EXCP_SEMIHOST 16 /* semihosting call */
#define EXCP_NOCP 17 /* v7M NOCP UsageFault */
#define ARMV7M_EXCP_RESET 1
#define ARMV7M_EXCP_NMI 2
@ -405,7 +407,12 @@ typedef struct CPUARMState {
uint32_t vecbase;
uint32_t basepri;
uint32_t control;
int current_sp;
uint32_t ccr; /* Configuration and Control */
uint32_t cfsr; /* Configurable Fault Status */
uint32_t hfsr; /* HardFault Status */
uint32_t dfsr; /* Debug Fault Status Register */
uint32_t mmfar; /* MemManage Fault Address */
uint32_t bfar; /* BusFault Address */
int exception;
} v7m;
@ -1087,6 +1094,53 @@ enum arm_cpu_mode {
#define ARM_IWMMXT_wCGR2 10
#define ARM_IWMMXT_wCGR3 11
/* V7M CCR bits */
FIELD(V7M_CCR, NONBASETHRDENA, 0, 1)
FIELD(V7M_CCR, USERSETMPEND, 1, 1)
FIELD(V7M_CCR, UNALIGN_TRP, 3, 1)
FIELD(V7M_CCR, DIV_0_TRP, 4, 1)
FIELD(V7M_CCR, BFHFNMIGN, 8, 1)
FIELD(V7M_CCR, STKALIGN, 9, 1)
FIELD(V7M_CCR, DC, 16, 1)
FIELD(V7M_CCR, IC, 17, 1)
/* V7M CFSR bits for MMFSR */
FIELD(V7M_CFSR, IACCVIOL, 0, 1)
FIELD(V7M_CFSR, DACCVIOL, 1, 1)
FIELD(V7M_CFSR, MUNSTKERR, 3, 1)
FIELD(V7M_CFSR, MSTKERR, 4, 1)
FIELD(V7M_CFSR, MLSPERR, 5, 1)
FIELD(V7M_CFSR, MMARVALID, 7, 1)
/* V7M CFSR bits for BFSR */
FIELD(V7M_CFSR, IBUSERR, 8 + 0, 1)
FIELD(V7M_CFSR, PRECISERR, 8 + 1, 1)
FIELD(V7M_CFSR, IMPRECISERR, 8 + 2, 1)
FIELD(V7M_CFSR, UNSTKERR, 8 + 3, 1)
FIELD(V7M_CFSR, STKERR, 8 + 4, 1)
FIELD(V7M_CFSR, LSPERR, 8 + 5, 1)
FIELD(V7M_CFSR, BFARVALID, 8 + 7, 1)
/* V7M CFSR bits for UFSR */
FIELD(V7M_CFSR, UNDEFINSTR, 16 + 0, 1)
FIELD(V7M_CFSR, INVSTATE, 16 + 1, 1)
FIELD(V7M_CFSR, INVPC, 16 + 2, 1)
FIELD(V7M_CFSR, NOCP, 16 + 3, 1)
FIELD(V7M_CFSR, UNALIGNED, 16 + 8, 1)
FIELD(V7M_CFSR, DIVBYZERO, 16 + 9, 1)
/* V7M HFSR bits */
FIELD(V7M_HFSR, VECTTBL, 1, 1)
FIELD(V7M_HFSR, FORCED, 30, 1)
FIELD(V7M_HFSR, DEBUGEVT, 31, 1)
/* V7M DFSR bits */
FIELD(V7M_DFSR, HALTED, 0, 1)
FIELD(V7M_DFSR, BKPT, 1, 1)
FIELD(V7M_DFSR, DWTTRAP, 2, 1)
FIELD(V7M_DFSR, VCATCH, 3, 1)
FIELD(V7M_DFSR, EXTERNAL, 4, 1)
/* If adding a feature bit which corresponds to a Linux ELF
* HWCAP bit, remember to update the feature-bit-to-hwcap
* mapping in linux-user/elfload.c:get_elf_hwcap().
@ -1763,12 +1817,6 @@ bool write_list_to_cpustate(ARMCPU *cpu);
*/
bool write_cpustate_to_list(ARMCPU *cpu);
/* Does the core conform to the "MicroController" profile. e.g. Cortex-M3.
Note the M in older cores (eg. ARM7TDMI) stands for Multiply. These are
conventional cores (ie. Application or Realtime profile). */
#define IS_M(env) arm_feature(env, ARM_FEATURE_M)
#define ARM_CPUID_TI915T 0x54029152
#define ARM_CPUID_TI925T 0x54029252

View File

@ -5947,14 +5947,19 @@ static uint32_t v7m_pop(CPUARMState *env)
}
/* Switch to V7M main or process stack pointer. */
static void switch_v7m_sp(CPUARMState *env, int process)
static void switch_v7m_sp(CPUARMState *env, bool new_spsel)
{
uint32_t tmp;
if (env->v7m.current_sp != process) {
bool old_spsel = env->v7m.control & R_V7M_CONTROL_SPSEL_MASK;
if (old_spsel != new_spsel) {
tmp = env->v7m.other_sp;
env->v7m.other_sp = env->regs[13];
env->regs[13] = tmp;
env->v7m.current_sp = process;
env->v7m.control = deposit32(env->v7m.control,
R_V7M_CONTROL_SPSEL_SHIFT,
R_V7M_CONTROL_SPSEL_LENGTH, new_spsel);
}
}
@ -5964,8 +5969,13 @@ static void do_v7m_exception_exit(CPUARMState *env)
uint32_t xpsr;
type = env->regs[15];
if (env->v7m.exception != 0)
if (env->v7m.exception != ARMV7M_EXCP_NMI) {
/* Auto-clear FAULTMASK on return from other than NMI */
env->daif &= ~PSTATE_F;
}
if (env->v7m.exception != 0) {
armv7m_nvic_complete_irq(env->nvic, env->v7m.exception);
}
/* Switch to the target stack. */
switch_v7m_sp(env, (type & 4) != 0);
@ -6014,6 +6024,30 @@ static void arm_log_exception(int idx)
}
}
static uint32_t arm_v7m_load_vector(ARMCPU *cpu)
{
CPUState *cs = CPU(cpu);
CPUARMState *env = &cpu->env;
MemTxResult result;
hwaddr vec = env->v7m.vecbase + env->v7m.exception * 4;
uint32_t addr;
addr = address_space_ldl(cs->as, vec,
MEMTXATTRS_UNSPECIFIED, &result);
if (result != MEMTX_OK) {
/* Architecturally this should cause a HardFault setting HSFR.VECTTBL,
* which would then be immediately followed by our failing to load
* the entry vector for that HardFault, which is a Lockup case.
* Since we don't model Lockup, we just report this guest error
* via cpu_abort().
*/
cpu_abort(cs, "Failed to read from exception vector table "
"entry %08x\n", (unsigned)vec);
}
return addr;
}
void arm_v7m_cpu_do_interrupt(CPUState *cs)
{
ARMCPU *cpu = ARM_CPU(cs);
@ -6025,8 +6059,9 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
arm_log_exception(cs->exception_index);
lr = 0xfffffff1;
if (env->v7m.current_sp)
if (env->v7m.control & R_V7M_CONTROL_SPSEL_MASK) {
lr |= 4;
}
if (env->v7m.exception == 0)
lr |= 8;
@ -6037,6 +6072,11 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
switch (cs->exception_index) {
case EXCP_UDEF:
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE);
env->v7m.cfsr |= R_V7M_CFSR_UNDEFINSTR_MASK;
return;
case EXCP_NOCP:
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE);
env->v7m.cfsr |= R_V7M_CFSR_NOCP_MASK;
return;
case EXCP_SWI:
/* The PC already points to the next instruction. */
@ -6075,10 +6115,8 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
return; /* Never happens. Keep compiler happy. */
}
/* Align stack pointer. */
/* ??? Should only do this if Configuration Control Register
STACKALIGN bit is set. */
if (env->regs[13] & 4) {
/* Align stack pointer if the guest wants that */
if ((env->regs[13] & 4) && (env->v7m.ccr & R_V7M_CCR_STKALIGN_MASK)) {
env->regs[13] -= 4;
xpsr |= 0x200;
}
@ -6095,7 +6133,7 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
/* Clear IT bits */
env->condexec_bits = 0;
env->regs[14] = lr;
addr = ldl_phys(cs->as, env->v7m.vecbase + env->v7m.exception * 4);
addr = arm_v7m_load_vector(cpu);
env->regs[15] = addr & 0xfffffffe;
env->thumb = addr & 1;
}
@ -6660,7 +6698,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
CPUARMState *env = &cpu->env;
unsigned int new_el = env->exception.target_el;
assert(!IS_M(env));
assert(!arm_feature(env, ARM_FEATURE_M));
arm_log_exception(cs->exception_index);
qemu_log_mask(CPU_LOG_INT, "...from EL%d to EL%d\n", arm_current_el(env),
@ -8243,27 +8281,38 @@ hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr,
uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
{
ARMCPU *cpu = arm_env_get_cpu(env);
uint32_t mask;
unsigned el = arm_current_el(env);
/* First handle registers which unprivileged can read */
switch (reg) {
case 0 ... 7: /* xPSR sub-fields */
mask = 0;
if ((reg & 1) && el) {
mask |= 0x000001ff; /* IPSR (unpriv. reads as zero) */
}
if (!(reg & 4)) {
mask |= 0xf8000000; /* APSR */
}
/* EPSR reads as zero */
return xpsr_read(env) & mask;
break;
case 20: /* CONTROL */
return env->v7m.control;
}
if (el == 0) {
return 0; /* unprivileged reads others as zero */
}
switch (reg) {
case 0: /* APSR */
return xpsr_read(env) & 0xf8000000;
case 1: /* IAPSR */
return xpsr_read(env) & 0xf80001ff;
case 2: /* EAPSR */
return xpsr_read(env) & 0xff00fc00;
case 3: /* xPSR */
return xpsr_read(env) & 0xff00fdff;
case 5: /* IPSR */
return xpsr_read(env) & 0x000001ff;
case 6: /* EPSR */
return xpsr_read(env) & 0x0700fc00;
case 7: /* IEPSR */
return xpsr_read(env) & 0x0700edff;
case 8: /* MSP */
return env->v7m.current_sp ? env->v7m.other_sp : env->regs[13];
return (env->v7m.control & R_V7M_CONTROL_SPSEL_MASK) ?
env->v7m.other_sp : env->regs[13];
case 9: /* PSP */
return env->v7m.current_sp ? env->regs[13] : env->v7m.other_sp;
return (env->v7m.control & R_V7M_CONTROL_SPSEL_MASK) ?
env->regs[13] : env->v7m.other_sp;
case 16: /* PRIMASK */
return (env->daif & PSTATE_I) != 0;
case 17: /* BASEPRI */
@ -8271,52 +8320,40 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
return env->v7m.basepri;
case 19: /* FAULTMASK */
return (env->daif & PSTATE_F) != 0;
case 20: /* CONTROL */
return env->v7m.control;
default:
/* ??? For debugging only. */
cpu_abort(CPU(cpu), "Unimplemented system register read (%d)\n", reg);
qemu_log_mask(LOG_GUEST_ERROR, "Attempt to read unknown special"
" register %d\n", reg);
return 0;
}
}
void HELPER(v7m_msr)(CPUARMState *env, uint32_t reg, uint32_t val)
{
ARMCPU *cpu = arm_env_get_cpu(env);
if (arm_current_el(env) == 0 && reg > 7) {
/* only xPSR sub-fields may be written by unprivileged */
return;
}
switch (reg) {
case 0: /* APSR */
xpsr_write(env, val, 0xf8000000);
break;
case 1: /* IAPSR */
xpsr_write(env, val, 0xf8000000);
break;
case 2: /* EAPSR */
xpsr_write(env, val, 0xfe00fc00);
break;
case 3: /* xPSR */
xpsr_write(env, val, 0xfe00fc00);
break;
case 5: /* IPSR */
/* IPSR bits are readonly. */
break;
case 6: /* EPSR */
xpsr_write(env, val, 0x0600fc00);
break;
case 7: /* IEPSR */
xpsr_write(env, val, 0x0600fc00);
case 0 ... 7: /* xPSR sub-fields */
/* only APSR is actually writable */
if (reg & 4) {
xpsr_write(env, val, 0xf8000000); /* APSR */
}
break;
case 8: /* MSP */
if (env->v7m.current_sp)
if (env->v7m.control & R_V7M_CONTROL_SPSEL_MASK) {
env->v7m.other_sp = val;
else
} else {
env->regs[13] = val;
}
break;
case 9: /* PSP */
if (env->v7m.current_sp)
if (env->v7m.control & R_V7M_CONTROL_SPSEL_MASK) {
env->regs[13] = val;
else
} else {
env->v7m.other_sp = val;
}
break;
case 16: /* PRIMASK */
if (val & 1) {
@ -8341,12 +8378,13 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t reg, uint32_t val)
}
break;
case 20: /* CONTROL */
env->v7m.control = val & 3;
switch_v7m_sp(env, (val & 2) != 0);
switch_v7m_sp(env, (val & R_V7M_CONTROL_SPSEL_MASK) != 0);
env->v7m.control = val & (R_V7M_CONTROL_SPSEL_MASK |
R_V7M_CONTROL_NPRIV_MASK);
break;
default:
/* ??? For debugging only. */
cpu_abort(CPU(cpu), "Unimplemented system register write (%d)\n", reg);
qemu_log_mask(LOG_GUEST_ERROR, "Attempt to write unknown special"
" register %d\n", reg);
return;
}
}

View File

@ -25,6 +25,8 @@
#ifndef TARGET_ARM_INTERNALS_H
#define TARGET_ARM_INTERNALS_H
#include "hw/registerfields.h"
/* register banks for CPU modes */
#define BANK_USRSYS 0
#define BANK_SVC 1
@ -75,6 +77,11 @@ static const char * const excnames[] = {
*/
#define GTIMER_SCALE 16
/* Bit definitions for the v7M CONTROL register */
FIELD(V7M_CONTROL, NPRIV, 0, 1)
FIELD(V7M_CONTROL, SPSEL, 1, 1)
FIELD(V7M_CONTROL, FPCA, 2, 1)
/*
* For AArch64, map a given EL to an index in the banked_spsr array.
* Note that this mapping and the AArch32 mapping defined in bank_number()

View File

@ -99,15 +99,19 @@ static bool m_needed(void *opaque)
static const VMStateDescription vmstate_m = {
.name = "cpu/m",
.version_id = 1,
.minimum_version_id = 1,
.version_id = 3,
.minimum_version_id = 3,
.needed = m_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT32(env.v7m.other_sp, ARMCPU),
VMSTATE_UINT32(env.v7m.vecbase, ARMCPU),
VMSTATE_UINT32(env.v7m.basepri, ARMCPU),
VMSTATE_UINT32(env.v7m.control, ARMCPU),
VMSTATE_INT32(env.v7m.current_sp, ARMCPU),
VMSTATE_UINT32(env.v7m.ccr, ARMCPU),
VMSTATE_UINT32(env.v7m.cfsr, ARMCPU),
VMSTATE_UINT32(env.v7m.hfsr, ARMCPU),
VMSTATE_UINT32(env.v7m.dfsr, ARMCPU),
VMSTATE_UINT32(env.v7m.mmfar, ARMCPU),
VMSTATE_UINT32(env.v7m.bfar, ARMCPU),
VMSTATE_INT32(env.v7m.exception, ARMCPU),
VMSTATE_END_OF_LIST()
}

View File

@ -10217,6 +10217,14 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
break;
case 6: case 7: case 14: case 15:
/* Coprocessor. */
if (arm_dc_feature(s, ARM_FEATURE_M)) {
/* We don't currently implement M profile FP support,
* so this entire space should give a NOCP fault.
*/
gen_exception_insn(s, 4, EXCP_NOCP, syn_uncategorized(),
default_exception_el(s));
break;
}
if (((insn >> 24) & 3) == 3) {
/* Translate into the equivalent ARM encoding. */
insn = (insn & 0xe2ffffff) | ((insn & (1 << 28)) >> 4) | (1 << 28);
@ -11719,12 +11727,12 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
break;
}
#else
if (dc->pc >= 0xfffffff0 && arm_dc_feature(dc, ARM_FEATURE_M)) {
/* We always get here via a jump, so know we are not in a
conditional execution block. */
gen_exception_internal(EXCP_EXCEPTION_EXIT);
dc->is_jmp = DISAS_EXC;
break;
if (arm_dc_feature(dc, ARM_FEATURE_M)) {
/* Branches to the magic exception-return addresses should
* already have been caught via the arm_v7m_unassigned_access hook,
* and never get here.
*/
assert(dc->pc < 0xfffffff0);
}
#endif