From ac2810defa9d4ba856adbaa9c899defecd8585de Mon Sep 17 00:00:00 2001 From: Cédric Le Goater Date: Fri, 27 Jan 2017 15:20:20 +0000 Subject: aspeed/smc: handle dummy bytes when doing fast reads in command mode When doing fast read, a certain amount of dummy bytes should be sent before the read. This number is configurable in the controler CE0 Control Register and needs to be modeled using fake transfers to the flash module. This only supports command mode. User mode requires more work and a possible extension of the m25p80 device model. Signed-off-by: Cédric Le Goater Acked-by: Marcin Krzemiński Message-id: 1484751701-2646-1-git-send-email-clg@kaod.org Signed-off-by: Peter Maydell --- hw/ssi/aspeed_smc.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'hw') diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index ae1ad2dba6..087b29e8da 100644 --- a/hw/ssi/aspeed_smc.c +++ b/hw/ssi/aspeed_smc.c @@ -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); } -- cgit v1.2.3-55-g7522 From 542b3478a00cb7ef51c259255b3ab1e2a7daada2 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 27 Jan 2017 15:20:21 +0000 Subject: armv7m: Replace armv7m.hack with unassigned_access handler For v7m we need to catch attempts to execute from special addresses at 0xfffffff0 and above. Previously we did this with the aid of a hacky special purpose lump of memory in the address space and a check in translate.c for whether we were translating code at those addresses. We can implement this more cleanly using a CPU unassigned access handler which throws the exception if the unassigned access is for one of the special addresses. Signed-off-by: Michael Davidsaver Reviewed-by: Alex Bennée Message-id: 1484937883-1068-3-git-send-email-peter.maydell@linaro.org [PMM: * drop the deletion of the "don't interrupt if PC is magic" code in arm_v7m_cpu_exec_interrupt() -- this is still required * don't generate an exception for unassigned accesses which aren't to the magic address -- although doing this is in theory correct in practice it will break currently working guests which rely on the RAZ/WI behaviour when they touch devices which we haven't modelled. * trigger EXCP_EXCEPTION_EXIT on is_exec, not !is_write ] Signed-off-by: Peter Maydell --- hw/arm/armv7m.c | 8 -------- target/arm/cpu.c | 28 ++++++++++++++++++++++++++++ target/arm/translate.c | 12 ++++++------ 3 files changed, 34 insertions(+), 14 deletions(-) (limited to 'hw') diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index 49d30782c8..0c9ca7bfa0 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -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; } diff --git a/target/arm/cpu.c b/target/arm/cpu.c index a941f6611b..907598968c 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -292,6 +292,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 +1043,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; } diff --git a/target/arm/translate.c b/target/arm/translate.c index c9186b6195..a7c2abeffe 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -11719,12 +11719,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 -- cgit v1.2.3-55-g7522 From feb0b1aa11f14ee71660aba46b46387d1f923c9e Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 27 Jan 2017 15:20:22 +0000 Subject: pflash_cfi01: fix per-device sector length in CFI table For configurations of the pflash_cfi01 device which set it up with a device-width not equal to the width (ie where we are emulating multiple narrow flash devices wired up in parallel), we were giving incorrect values in the CFI data table: (1) the sector length entry should specify the sector length for a single device, not the length for the overall collection of devices (2) the number of blocks per device must not be divided by the number of devices because the resulting device size would not match the overall size (3) this then means that the overall write block size must be modified depending on the number of devices because the entry is per device and when the guest writes into the flash it calculates the write size by using the CFI entry (write size per device) multiplied by the number of chips. (It would alternatively be possible to modify the write block size in the CFI table (currently hardcoded at 2048) and leave the overall write block size alone.) This commit corrects these bugs, and adds a hw-compat property to retain the old behaviour on 2.8 and earlier versions. (The only board we have which uses this sort of flash config and has machine versioning is the "virt" board -- the PC uses a single flash device and so behaviour is unaffected whether using old-multiple-chip-handling or not.) Here is a configuration example from the vexpress board: VEXPRESS_FLASH_SIZE = 64M VEXPRESS_FLASH_SECT_SIZE 256K num-blocks = VEXPRESS_FLASH_SIZE / VEXPRESS_FLASH_SECT_SIZE = 256 sector-length = 256K width = 4 device-width = 2 The code will fill the CFI entry with the following entries: num-blocks = 256 sector-length = 128K writeblock_size = 2048 This results in two chips, each with 256 * 128K = 32M device size and a write block size of 2048. A sector erase will be sent to both chips, thus 256K must be erased. When the guest sends a block write command, it will write 4096 bytes data at once (2048 per device). Signed-off-by: David Engraf Reviewed-by: Peter Maydell [PMM: cleaned up and expanded commit message] Signed-off-by: Peter Maydell --- hw/block/pflash_cfi01.c | 22 +++++++++++++++++----- include/hw/compat.h | 4 ++++ 2 files changed, 21 insertions(+), 5 deletions(-) (limited to 'hw') diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index 5f0ee9db00..71b98a3eef 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -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(), }; diff --git a/include/hw/compat.h b/include/hw/compat.h index 34e9b4a660..ee0dd1b5df 100644 --- a/include/hw/compat.h +++ b/include/hw/compat.h @@ -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 \ -- cgit v1.2.3-55-g7522 From d713ea6c464918f87d1dd480520dd4aedb685d9a Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 27 Jan 2017 15:20:22 +0000 Subject: armv7m_nvic: keep a pointer to the CPU Many NVIC operations access the CPU state, so store a pointer in struct nvic_state rather than fetching it via qemu_get_cpu() every time we need it. As with the arm_gicv3_common code, we currently just call qemu_get_cpu() in the NVIC's realize method, but in future we might want to use a QOM property to pass the CPU to the NVIC. This imposes an ordering requirement that the CPU is realized before the NVIC, but that is always true since both are dealt with in armv7m_init(). Signed-off-by: Michael Davidsaver Reviewed-by: Peter Maydell Reviewed-by: Alex Bennée Message-id: 1485285380-10565-3-git-send-email-peter.maydell@linaro.org [PMM: Use qemu_get_cpu(0) rather than first_cpu; expand commit message] Signed-off-by: Peter Maydell --- hw/intc/armv7m_nvic.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'hw') diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 06d8db6bd6..81dcb83040 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -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; @@ -296,7 +294,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 +347,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. */ @@ -495,6 +492,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 */ -- cgit v1.2.3-55-g7522 From e6b332097d1a4713173a82f17d039b4c78bc6f59 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 27 Jan 2017 15:20:23 +0000 Subject: armv7m: implement CCR, CFSR, HFSR, DFSR, BFAR, and MMFAR Implement the v7M system registers CCR, CFSR, HFSR, DFSR, BFAR and MMFAR. For the moment these simply read as written (with some basic handling of RAZ/WI bits and W1C semantics). Signed-off-by: Michael Davidsaver Reviewed-by: Alex Bennée Message-id: 1485285380-10565-5-git-send-email-peter.maydell@linaro.org [PMM: drop warning about setting unimplemented CCR bits; tweak commit message; add DFSR] Signed-off-by: Peter Maydell --- hw/intc/armv7m_nvic.c | 42 ++++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) (limited to 'hw') diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 81dcb83040..60e72d7395 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -228,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); @@ -248,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; @@ -366,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 @@ -378,13 +390,23 @@ 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) { -- cgit v1.2.3-55-g7522 From bdd04fc76a78d61ae0f0e93ce345f9cf2e49a9a8 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 27 Jan 2017 15:20:24 +0000 Subject: armv7m: Honour CCR.USERSETMPEND The CCR.USERSETMPEND bit has to be set to permit unprivileged code to write to the Software Triggered Interrupt register; honour this bit rather than letting any code write to the register. Signed-off-by: Michael Davidsaver Reviewed-by: Alex Bennée Message-id: 1485285380-10565-9-git-send-email-peter.maydell@linaro.org [PMM: Tweak commit message, comment, phrasing of condition] Signed-off-by: Peter Maydell --- hw/intc/armv7m_nvic.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 60e72d7395..fe5c303de9 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -409,7 +409,10 @@ static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value) "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; -- cgit v1.2.3-55-g7522 From d05a86285cacdcbfdd97e437d156545666fa5641 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 27 Jan 2017 15:20:25 +0000 Subject: arm: stellaris: make MII accesses complete immediately When the guest attempts to start an MII register access via the MCTL register, clear the START bit, so that when the guest reads it back the register transaction will be signalled as having completed. This avoids the guest spinning as it polls the START bit waiting for it to clear (which it previously never would). The MII registers themselves still aren't implemented, but at least we can avoid guests spending quite so much time busy waiting. Signed-off-by: Michael Davidsaver Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell Message-id: 1484938222-1423-1-git-send-email-peter.maydell@linaro.org [PMM: expand commit message] Signed-off-by: Peter Maydell --- hw/net/stellaris_enet.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/net/stellaris_enet.c b/hw/net/stellaris_enet.c index 957730e023..04bd10ada3 100644 --- a/hw/net/stellaris_enet.c +++ b/hw/net/stellaris_enet.c @@ -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; -- cgit v1.2.3-55-g7522 From e62694a078f182c822a7b6d3976b1bcc72e78ec2 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 27 Jan 2017 15:20:25 +0000 Subject: hw/char/exynos4210_uart: Drop unused local variable frame_size The frame_size local variable in exynos4210_uart_update_parameters() is calculated but never used (and has been this way since the device was introduced in commit e5a4914efc7). The qemu_chr_fe_ioctl() doesn't need this information (if it really wanted it it could calculate it from the parity/data_bits/stop_bits), so just drop the variable entirely. Fixes: https://bugs.launchpad.net/bugs/1655702 Signed-off-by: Peter Maydell Message-id: 1484589515-26353-1-git-send-email-peter.maydell@linaro.org --- hw/char/exynos4210_uart.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'hw') diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c index 820d1abeb9..0cd3dd3958 100644 --- a/hw/char/exynos4210_uart.c +++ b/hw/char/exynos4210_uart.c @@ -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) + -- cgit v1.2.3-55-g7522 From d87576e38df760ef1cb635197d51f207e2a8eda9 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 27 Jan 2017 15:20:25 +0000 Subject: arm_gicv3: Fix broken logic in ELRSR calculation Fix a broken expression in the calculation of ELRSR register bits: instead of "(lr & ICH_LR_EL2_HW) == 1" we want to check for != 0, because the HW bit is not bit 0 so a test for == 1 is always false. Fixes: https://bugs.launchpad.net/bugs/1658506 Signed-off-by: Peter Maydell Reviewed-by: Thomas Huth Message-id: 1485255993-6322-1-git-send-email-peter.maydell@linaro.org --- hw/intc/arm_gicv3_cpuif.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index a9ee7fddf9..c25ee03556 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -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); } } -- cgit v1.2.3-55-g7522 From 146871c33eb70ca7090a0a55e69e5a8f9b5eb102 Mon Sep 17 00:00:00 2001 From: Prasad J Pandit Date: Fri, 27 Jan 2017 15:20:25 +0000 Subject: dma: omap: check dma channel data_type When setting dma channel 'data_type', if (value & 3) == 3, the set 'data_type' is said to be bad. This also leads to an OOB access in 'omap_dma_transfer_generic', while doing cpu_physical_memory_r/w operations. Add check to avoid it. Reported-by: Jiang Xin Signed-off-by: Prasad J Pandit Message-id: 20170127120528.30959-1-ppandit@redhat.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/dma/omap_dma.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'hw') diff --git a/hw/dma/omap_dma.c b/hw/dma/omap_dma.c index f6f86f9639..45dfe7aadd 100644 --- a/hw/dma/omap_dma.c +++ b/hw/dma/omap_dma.c @@ -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 */ -- cgit v1.2.3-55-g7522