Message ID | 20200301084427.93823-1-root@stephanos.io (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | hw/arm/stm32f405: Add preliminary flash interface emulation support | expand |
On Sun, Mar 1, 2020 at 12:47 AM Stephanos Ioannidis <root@stephanos.io> wrote: > > The flash interface (FLASHIF) peripheral provides a control interface > for the SoC embedded flash memory on the STM32F4xx series devices. > > This commit adds preliminary support for the flash interface peripheral > emulation, in order to support proper emulation of the firmware images > that use the STM32Cube driver, which configures and validates the > FLASH_ACR register during system initialisation. > > Signed-off-by: Stephanos Ioannidis <root@stephanos.io> Hey Stephanos, I think a lot of comments from your other patch apply to this patch as well (about bit fields and splitting the patch specifically). Do you mind sending a v2 addressing those comments? Alistair > --- > hw/arm/Kconfig | 1 + > hw/arm/stm32f405_soc.c | 15 +- > hw/misc/Kconfig | 3 + > hw/misc/Makefile.objs | 1 + > hw/misc/stm32f4xx_flashif.c | 215 ++++++++++++++++++++++++++++ > hw/misc/trace-events | 4 + > include/hw/arm/stm32f405_soc.h | 2 + > include/hw/misc/stm32f4xx_flashif.h | 144 +++++++++++++++++++ > 8 files changed, 384 insertions(+), 1 deletion(-) > create mode 100644 hw/misc/stm32f4xx_flashif.c > create mode 100644 include/hw/misc/stm32f4xx_flashif.h > > diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig > index 3d86691ae0..179696ec91 100644 > --- a/hw/arm/Kconfig > +++ b/hw/arm/Kconfig > @@ -314,6 +314,7 @@ config STM32F205_SOC > config STM32F405_SOC > bool > select ARM_V7M > + select STM32F4XX_FLASHIF > select STM32F4XX_SYSCFG > select STM32F4XX_EXTI > > diff --git a/hw/arm/stm32f405_soc.c b/hw/arm/stm32f405_soc.c > index 9bcad97853..72b16910c7 100644 > --- a/hw/arm/stm32f405_soc.c > +++ b/hw/arm/stm32f405_soc.c > @@ -30,6 +30,7 @@ > #include "hw/arm/stm32f405_soc.h" > #include "hw/misc/unimp.h" > > +#define FLASHIF_ADDR 0x40023C00 > #define SYSCFG_ADD 0x40013800 > static const uint32_t usart_addr[] = { 0x40011000, 0x40004400, 0x40004800, > 0x40004C00, 0x40005000, 0x40011400, > @@ -59,6 +60,9 @@ static void stm32f405_soc_initfn(Object *obj) > sysbus_init_child_obj(obj, "armv7m", &s->armv7m, sizeof(s->armv7m), > TYPE_ARMV7M); > > + sysbus_init_child_obj(obj, "flashif", &s->flashif, sizeof(s->flashif), > + TYPE_STM32F4XX_FLASHIF); > + > sysbus_init_child_obj(obj, "syscfg", &s->syscfg, sizeof(s->syscfg), > TYPE_STM32F4XX_SYSCFG); > > @@ -130,6 +134,16 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) > return; > } > > + /* Flash interface */ > + dev = DEVICE(&s->flashif); > + object_property_set_bool(OBJECT(&s->flashif), true, "realized", &err); > + if (err != NULL) { > + error_propagate(errp, err); > + return; > + } > + busdev = SYS_BUS_DEVICE(dev); > + sysbus_mmio_map(busdev, 0, FLASHIF_ADDR); > + > /* System configuration controller */ > dev = DEVICE(&s->syscfg); > object_property_set_bool(OBJECT(&s->syscfg), true, "realized", &err); > @@ -261,7 +275,6 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) > create_unimplemented_device("GPIOI", 0x40022000, 0x400); > create_unimplemented_device("CRC", 0x40023000, 0x400); > create_unimplemented_device("RCC", 0x40023800, 0x400); > - create_unimplemented_device("Flash Int", 0x40023C00, 0x400); > create_unimplemented_device("BKPSRAM", 0x40024000, 0x400); > create_unimplemented_device("DMA1", 0x40026000, 0x400); > create_unimplemented_device("DMA2", 0x40026400, 0x400); > diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig > index bdd77d8020..e333a955b2 100644 > --- a/hw/misc/Kconfig > +++ b/hw/misc/Kconfig > @@ -79,6 +79,9 @@ config IMX > select SSI > select USB_EHCI_SYSBUS > > +config STM32F4XX_FLASHIF > + bool > + > config STM32F2XX_SYSCFG > bool > > diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs > index da993f45b7..1aea0b9bb9 100644 > --- a/hw/misc/Makefile.objs > +++ b/hw/misc/Makefile.objs > @@ -58,6 +58,7 @@ 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 > +common-obj-$(CONFIG_STM32F4XX_FLASHIF) += stm32f4xx_flashif.o > common-obj-$(CONFIG_STM32F2XX_SYSCFG) += stm32f2xx_syscfg.o > common-obj-$(CONFIG_STM32F4XX_SYSCFG) += stm32f4xx_syscfg.o > common-obj-$(CONFIG_STM32F4XX_EXTI) += stm32f4xx_exti.o > diff --git a/hw/misc/stm32f4xx_flashif.c b/hw/misc/stm32f4xx_flashif.c > new file mode 100644 > index 0000000000..d280fc5b2c > --- /dev/null > +++ b/hw/misc/stm32f4xx_flashif.c > @@ -0,0 +1,215 @@ > +/* > + * STM32F4xx FLASHIF > + * > + * Copyright (c) 2020 Stephanos Ioannidis <root@stephanos.io> > + * > + * Permission is hereby granted, free of charge, to any person obtaining a copy > + * of this software and associated documentation files (the "Software"), to deal > + * in the Software without restriction, including without limitation the rights > + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > + * copies of the Software, and to permit persons to whom the Software is > + * furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice shall be included in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > + * THE SOFTWARE. > + */ > + > +#include "qemu/osdep.h" > +#include "qemu/log.h" > +#include "trace.h" > +#include "hw/irq.h" > +#include "migration/vmstate.h" > +#include "hw/misc/stm32f4xx_flashif.h" > + > +static void stm32f4xx_flashif_reset(DeviceState *dev) > +{ > + STM32F4xxFlashIfState *s = STM32F4XX_FLASHIF(dev); > + > + /* Initialise states */ > + s->cr_key_index = 0; > + s->optcr_key_index = 0; > + > + /* Initialise register values */ > + s->flash_acr.reg = 0x00000000; > + s->flash_keyr.reg = 0x00000000; > + s->flash_optkeyr.reg = 0x00000000; > + s->flash_sr.reg = 0x00000000; > + s->flash_cr.reg = 0x80000000; > + s->flash_optcr.reg = 0x0FFFAAED; > +} > + > +static uint64_t stm32f4xx_flashif_read(void * opaque, hwaddr addr, > + unsigned int size) > +{ > + STM32F4xxFlashIfState *s = opaque; > + > + trace_stm32f4xx_flashif_read(addr); > + > + switch (addr) { > + case FLASH_ACR: > + return s->flash_acr.reg; > + case FLASH_SR: > + return s->flash_sr.reg; > + case FLASH_CR: > + return s->flash_cr.reg; > + case FLASH_OPTCR: > + return s->flash_optcr.reg; > + default: > + qemu_log_mask( > + LOG_GUEST_ERROR, > + "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); > + return 0; > + } > +} > + > +static void flash_acr_write(STM32F4xxFlashIfState *s, FlashAcrType val) > +{ > + /* Set latency */ > + s->flash_acr.latency = val.latency; > + /* Set prefetch status */ > + s->flash_acr.prften = val.prften; > + /* Set instruction cache status */ > + s->flash_acr.icen = val.icen; > + /* Set data cache status */ > + s->flash_acr.dcen = val.dcen; > +} > + > +static void flash_cr_write(STM32F4xxFlashIfState *s, FlashCrType val) > +{ > + /* Lock FLASH_CR if lock bit is set */ > + if (val.lock) { > + s->flash_cr.lock = 1; > + s->cr_key_index = 0; > + return; > + } > +} > + > +static void flash_optcr_write(STM32F4xxFlashIfState *s, FlashOptcrType val) > +{ > + /* Lock FLASH_OPTCR if lock bit is set */ > + if (val.optlock) { > + s->flash_optcr.optlock = 1; > + s->optcr_key_index = 0; > + return; > + } > +} > + > +static void stm32f4xx_flashif_write(void *opaque, hwaddr addr, > + uint64_t val64, unsigned int size) > +{ > + STM32F4xxFlashIfState *s = opaque; > + uint32_t value = val64; > + > + trace_stm32f4xx_flashif_write(value, addr); > + > + switch (addr) { > + case FLASH_ACR: > + flash_acr_write(s, (FlashAcrType)value); > + return; > + case FLASH_KEYR: > + if (s->cr_key_index == 0 && value == 0x45670123) { > + s->cr_key_index = 1; > + } else if (s->cr_key_index == 1 && value == 0xCDEF89AB) { > + /* Valid key; unlock FLASH_CR */ > + s->flash_cr.lock = 0; > + s->cr_key_index = 0; > + } else { > + /* Invalid key; permanently lock FLASH_CR until reset */ > + s->flash_cr.lock = 1; > + s->cr_key_index = -1; > + } > + return; > + case FLASH_OPTKEYR: > + if (s->optcr_key_index == 0 && value == 0x08192A3B) { > + s->optcr_key_index = 1; > + } else if (s->optcr_key_index == 1 && value == 0x4C5D6E7F) { > + /* Valid key; unlock FLASH_OPTCR */ > + s->flash_optcr.optlock = 0; > + s->optcr_key_index = 0; > + } else { > + /* Invalid key; lock FLASH_OPTCR until reset */ > + s->flash_optcr.optlock = 1; > + s->optcr_key_index = -1; > + } > + return; > + case FLASH_SR: > + if (s->flash_sr.eop) s->flash_sr.eop = 0; > + if (s->flash_sr.operr) s->flash_sr.operr = 0; > + if (s->flash_sr.wrperr) s->flash_sr.wrperr = 0; > + if (s->flash_sr.pgaerr) s->flash_sr.pgaerr = 0; > + if (s->flash_sr.pgperr) s->flash_sr.pgperr = 0; > + if (s->flash_sr.pgserr) s->flash_sr.pgserr = 0; > + return; > + case FLASH_CR: > + flash_cr_write(s, (FlashCrType)value); > + return; > + case FLASH_OPTCR: > + flash_optcr_write(s, (FlashOptcrType)value); > + return; > + default: > + qemu_log_mask( > + LOG_GUEST_ERROR, > + "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); > + } > +} > + > +static const MemoryRegionOps stm32f4xx_flashif_ops = { > + .read = stm32f4xx_flashif_read, > + .write = stm32f4xx_flashif_write, > + .endianness = DEVICE_NATIVE_ENDIAN > +}; > + > +static void stm32f4xx_flashif_init(Object *obj) > +{ > + STM32F4xxFlashIfState *s = STM32F4XX_FLASHIF(obj); > + > + memory_region_init_io(&s->mmio, obj, &stm32f4xx_flashif_ops, s, > + TYPE_STM32F4XX_FLASHIF, 0x400); > + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); > +} > + > +static const VMStateDescription vmstate_stm32f4xx_flashif = { > + .name = TYPE_STM32F4XX_FLASHIF, > + .version_id = 1, > + .minimum_version_id = 1, > + .fields = (VMStateField[]) { > + VMSTATE_UINT32(flash_acr.reg, STM32F4xxFlashIfState), > + VMSTATE_UINT32(flash_keyr.reg, STM32F4xxFlashIfState), > + VMSTATE_UINT32(flash_optkeyr.reg, STM32F4xxFlashIfState), > + VMSTATE_UINT32(flash_sr.reg, STM32F4xxFlashIfState), > + VMSTATE_UINT32(flash_cr.reg, STM32F4xxFlashIfState), > + VMSTATE_UINT32(flash_optcr.reg, STM32F4xxFlashIfState), > + VMSTATE_END_OF_LIST() > + } > +}; > + > +static void stm32f4xx_flashif_class_init(ObjectClass *klass, void *data) > +{ > + DeviceClass *dc = DEVICE_CLASS(klass); > + > + dc->reset = stm32f4xx_flashif_reset; > + dc->vmsd = &vmstate_stm32f4xx_flashif; > +} > + > +static const TypeInfo stm32f4xx_flashif_info = { > + .name = TYPE_STM32F4XX_FLASHIF, > + .parent = TYPE_SYS_BUS_DEVICE, > + .instance_size = sizeof(STM32F4xxFlashIfState), > + .instance_init = stm32f4xx_flashif_init, > + .class_init = stm32f4xx_flashif_class_init > +}; > + > +static void stm32f4xx_flashif_register_types(void) > +{ > + type_register_static(&stm32f4xx_flashif_info); > +} > + > +type_init(stm32f4xx_flashif_register_types) > diff --git a/hw/misc/trace-events b/hw/misc/trace-events > index 7f0f5dff3a..bd9a5dd483 100644 > --- a/hw/misc/trace-events > +++ b/hw/misc/trace-events > @@ -84,6 +84,10 @@ mos6522_set_sr_int(void) "set sr_int" > mos6522_write(uint64_t addr, uint64_t val) "reg=0x%"PRIx64 " val=0x%"PRIx64 > mos6522_read(uint64_t addr, unsigned val) "reg=0x%"PRIx64 " val=0x%x" > > +# stm32f4xx_flashif > +stm32f4xx_flashif_read(uint64_t addr) "reg read: addr: 0x%" PRIx64 " " > +stm32f4xx_flashif_write(uint64_t addr, uint64_t data) "reg write: addr: 0x%" PRIx64 " val: 0x%" PRIx64 "" > + > # stm32f4xx_syscfg > stm32f4xx_syscfg_set_irq(int gpio, int line, int level) "Interupt: GPIO: %d, Line: %d; Level: %d" > stm32f4xx_pulse_exti(int irq) "Pulse EXTI: %d" > diff --git a/include/hw/arm/stm32f405_soc.h b/include/hw/arm/stm32f405_soc.h > index 1fe97f8c3a..a94c3c51ac 100644 > --- a/include/hw/arm/stm32f405_soc.h > +++ b/include/hw/arm/stm32f405_soc.h > @@ -25,6 +25,7 @@ > #ifndef HW_ARM_STM32F405_SOC_H > #define HW_ARM_STM32F405_SOC_H > > +#include "hw/misc/stm32f4xx_flashif.h" > #include "hw/misc/stm32f4xx_syscfg.h" > #include "hw/timer/stm32f2xx_timer.h" > #include "hw/char/stm32f2xx_usart.h" > @@ -57,6 +58,7 @@ typedef struct STM32F405State { > > ARMv7MState armv7m; > > + STM32F4xxFlashIfState flashif; > STM32F4xxSyscfgState syscfg; > STM32F4xxExtiState exti; > STM32F2XXUsartState usart[STM_NUM_USARTS]; > diff --git a/include/hw/misc/stm32f4xx_flashif.h b/include/hw/misc/stm32f4xx_flashif.h > new file mode 100644 > index 0000000000..e364ca39c7 > --- /dev/null > +++ b/include/hw/misc/stm32f4xx_flashif.h > @@ -0,0 +1,144 @@ > +/* > + * STM32F4xx FLASHIF > + * > + * Copyright (c) 2020 Stephanos Ioannidis <root@stephanos.io> > + * > + * Permission is hereby granted, free of charge, to any person obtaining a copy > + * of this software and associated documentation files (the "Software"), to deal > + * in the Software without restriction, including without limitation the rights > + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > + * copies of the Software, and to permit persons to whom the Software is > + * furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice shall be included in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > + * THE SOFTWARE. > + */ > + > +#ifndef HW_STM_FLASHIF_H > +#define HW_STM_FLASHIF_H > + > +#include "hw/sysbus.h" > +#include "hw/hw.h" > + > +#define TYPE_STM32F4XX_FLASHIF "stm32f4xx-flashif" > +#define STM32F4XX_FLASHIF(obj) \ > + OBJECT_CHECK(STM32F4xxFlashIfState, (obj), TYPE_STM32F4XX_FLASHIF) > + > +#define FLASH_ACR 0x00 > +#define FLASH_KEYR 0x04 > +#define FLASH_OPTKEYR 0x08 > +#define FLASH_SR 0x0C > +#define FLASH_CR 0x10 > +#define FLASH_OPTCR 0x14 > + > +typedef union { > + struct { > + uint32_t latency : 3; > + uint32_t reserved0 : 5; > + uint32_t prften : 1; > + uint32_t icen : 1; > + uint32_t dcen : 1; > + uint32_t icrst : 1; > + uint32_t dcrst : 1; > + uint32_t reserved1 : 19; > + }; > + uint32_t reg; > +} FlashAcrType; > + > +typedef union { > + struct { > + uint32_t key : 32; > + }; > + uint32_t reg; > +} FlashKeyrType; > + > +typedef union { > + struct { > + uint32_t optkey : 32; > + }; > + uint32_t reg; > +} FlashOptkeyrType; > + > +typedef union { > + struct { > + uint32_t eop : 1; > + uint32_t operr : 1; > + uint32_t reserved0 : 2; > + uint32_t wrperr : 1; > + uint32_t pgaerr : 1; > + uint32_t pgperr : 1; > + uint32_t pgserr : 1; > + uint32_t reserved1 : 8; > + uint32_t bsy : 1; > + uint32_t reserved2 : 15; > + }; > + uint32_t reg; > +} FlashSrType; > + > +typedef union { > + struct { > + uint32_t pg : 1; > + uint32_t ser : 1; > + uint32_t mer : 1; > + uint32_t snb : 4; > + uint32_t reserved0 : 1; > + uint32_t psize : 2; > + uint32_t reserved1 : 6; > + uint32_t strt : 1; > + uint32_t reserved2 : 7; > + uint32_t eopie : 1; > + uint32_t reserved3 : 6; > + uint32_t lock : 1; > + }; > + uint32_t reg; > +} FlashCrType; > + > +typedef union { > + struct { > + uint32_t optlock : 1; > + uint32_t optstrt : 1; > + uint32_t bor_lev : 2; > + uint32_t reserved0 : 1; > + uint32_t wdg_sw : 1; > + uint32_t nrst_stop : 1; > + uint32_t nrst_stdby : 1; > + uint32_t rdp : 8; > + uint32_t nwrp : 12; > + uint32_t reserved1 : 4; > + }; > + uint32_t reg; > +} FlashOptcrType; > + > +typedef struct { > + /* <private> */ > + SysBusDevice parent_obj; > + > + /* <public> */ > + MemoryRegion mmio; > + > + int32_t cr_key_index; > + int32_t optcr_key_index; > + > + /* Access control register (FLASH_ACR) */ > + FlashAcrType flash_acr; > + /* Key register (FLASH_KEYR) */ > + FlashKeyrType flash_keyr; > + /* Option key register (FLASH_OPTKEYR) */ > + FlashOptkeyrType flash_optkeyr; > + /* Status register (FLASH_SR) */ > + FlashSrType flash_sr; > + /* Control register (FLASH_CR) */ > + FlashCrType flash_cr; > + /* Option control register (FLASH_OPTCR) */ > + FlashOptcrType flash_optcr; > +} STM32F4xxFlashIfState; > + > +#endif > -- > 2.17.1 > >
> I think a lot of comments from your other patch apply to this patch as well (about bit fields and splitting the patch specifically). Certainly does, I will send the v2 for this as well. Stephanos -----Original Message----- From: Alistair Francis <alistair23@gmail.com> Sent: Friday, March 6, 2020 8:08 AM To: Stephanos Ioannidis <root@stephanos.io> Cc: Peter Maydell <peter.maydell@linaro.org>; Alistair Francis <alistair@alistair23.me>; open list:All patches CC here <qemu-devel@nongnu.org>; open list:ARM TCG CPUs <qemu-arm@nongnu.org> Subject: Re: [PATCH] hw/arm/stm32f405: Add preliminary flash interface emulation support On Sun, Mar 1, 2020 at 12:47 AM Stephanos Ioannidis <root@stephanos.io> wrote: > > The flash interface (FLASHIF) peripheral provides a control interface > for the SoC embedded flash memory on the STM32F4xx series devices. > > This commit adds preliminary support for the flash interface > peripheral emulation, in order to support proper emulation of the > firmware images that use the STM32Cube driver, which configures and > validates the FLASH_ACR register during system initialisation. > > Signed-off-by: Stephanos Ioannidis <root@stephanos.io> Hey Stephanos, I think a lot of comments from your other patch apply to this patch as well (about bit fields and splitting the patch specifically). Do you mind sending a v2 addressing those comments? Alistair > --- > hw/arm/Kconfig | 1 + > hw/arm/stm32f405_soc.c | 15 +- > hw/misc/Kconfig | 3 + > hw/misc/Makefile.objs | 1 + > hw/misc/stm32f4xx_flashif.c | 215 ++++++++++++++++++++++++++++ > hw/misc/trace-events | 4 + > include/hw/arm/stm32f405_soc.h | 2 + > include/hw/misc/stm32f4xx_flashif.h | 144 +++++++++++++++++++ > 8 files changed, 384 insertions(+), 1 deletion(-) create mode 100644 > hw/misc/stm32f4xx_flashif.c create mode 100644 > include/hw/misc/stm32f4xx_flashif.h > > diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index > 3d86691ae0..179696ec91 100644 > --- a/hw/arm/Kconfig > +++ b/hw/arm/Kconfig > @@ -314,6 +314,7 @@ config STM32F205_SOC config STM32F405_SOC > bool > select ARM_V7M > + select STM32F4XX_FLASHIF > select STM32F4XX_SYSCFG > select STM32F4XX_EXTI > > diff --git a/hw/arm/stm32f405_soc.c b/hw/arm/stm32f405_soc.c index > 9bcad97853..72b16910c7 100644 > --- a/hw/arm/stm32f405_soc.c > +++ b/hw/arm/stm32f405_soc.c > @@ -30,6 +30,7 @@ > #include "hw/arm/stm32f405_soc.h" > #include "hw/misc/unimp.h" > > +#define FLASHIF_ADDR 0x40023C00 > #define SYSCFG_ADD 0x40013800 > static const uint32_t usart_addr[] = { 0x40011000, 0x40004400, 0x40004800, > 0x40004C00, 0x40005000, > 0x40011400, @@ -59,6 +60,9 @@ static void stm32f405_soc_initfn(Object *obj) > sysbus_init_child_obj(obj, "armv7m", &s->armv7m, sizeof(s->armv7m), > TYPE_ARMV7M); > > + sysbus_init_child_obj(obj, "flashif", &s->flashif, sizeof(s->flashif), > + TYPE_STM32F4XX_FLASHIF); > + > sysbus_init_child_obj(obj, "syscfg", &s->syscfg, sizeof(s->syscfg), > TYPE_STM32F4XX_SYSCFG); > > @@ -130,6 +134,16 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) > return; > } > > + /* Flash interface */ > + dev = DEVICE(&s->flashif); > + object_property_set_bool(OBJECT(&s->flashif), true, "realized", &err); > + if (err != NULL) { > + error_propagate(errp, err); > + return; > + } > + busdev = SYS_BUS_DEVICE(dev); > + sysbus_mmio_map(busdev, 0, FLASHIF_ADDR); > + > /* System configuration controller */ > dev = DEVICE(&s->syscfg); > object_property_set_bool(OBJECT(&s->syscfg), true, "realized", > &err); @@ -261,7 +275,6 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) > create_unimplemented_device("GPIOI", 0x40022000, 0x400); > create_unimplemented_device("CRC", 0x40023000, 0x400); > create_unimplemented_device("RCC", 0x40023800, 0x400); > - create_unimplemented_device("Flash Int", 0x40023C00, 0x400); > create_unimplemented_device("BKPSRAM", 0x40024000, 0x400); > create_unimplemented_device("DMA1", 0x40026000, 0x400); > create_unimplemented_device("DMA2", 0x40026400, 0x400); > diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index > bdd77d8020..e333a955b2 100644 > --- a/hw/misc/Kconfig > +++ b/hw/misc/Kconfig > @@ -79,6 +79,9 @@ config IMX > select SSI > select USB_EHCI_SYSBUS > > +config STM32F4XX_FLASHIF > + bool > + > config STM32F2XX_SYSCFG > bool > > diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index > da993f45b7..1aea0b9bb9 100644 > --- a/hw/misc/Makefile.objs > +++ b/hw/misc/Makefile.objs > @@ -58,6 +58,7 @@ 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 > +common-obj-$(CONFIG_STM32F4XX_FLASHIF) += stm32f4xx_flashif.o > common-obj-$(CONFIG_STM32F2XX_SYSCFG) += stm32f2xx_syscfg.o > common-obj-$(CONFIG_STM32F4XX_SYSCFG) += stm32f4xx_syscfg.o > common-obj-$(CONFIG_STM32F4XX_EXTI) += stm32f4xx_exti.o diff --git > a/hw/misc/stm32f4xx_flashif.c b/hw/misc/stm32f4xx_flashif.c new file > mode 100644 index 0000000000..d280fc5b2c > --- /dev/null > +++ b/hw/misc/stm32f4xx_flashif.c > @@ -0,0 +1,215 @@ > +/* > + * STM32F4xx FLASHIF > + * > + * Copyright (c) 2020 Stephanos Ioannidis <root@stephanos.io> > + * > + * Permission is hereby granted, free of charge, to any person > +obtaining a copy > + * of this software and associated documentation files (the > +"Software"), to deal > + * in the Software without restriction, including without limitation > +the rights > + * to use, copy, modify, merge, publish, distribute, sublicense, > +and/or sell > + * copies of the Software, and to permit persons to whom the Software > +is > + * furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice shall be > +included in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, > +EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF > +MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT > +SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES > +OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, > +ARISING FROM, > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER > +DEALINGS IN > + * THE SOFTWARE. > + */ > + > +#include "qemu/osdep.h" > +#include "qemu/log.h" > +#include "trace.h" > +#include "hw/irq.h" > +#include "migration/vmstate.h" > +#include "hw/misc/stm32f4xx_flashif.h" > + > +static void stm32f4xx_flashif_reset(DeviceState *dev) { > + STM32F4xxFlashIfState *s = STM32F4XX_FLASHIF(dev); > + > + /* Initialise states */ > + s->cr_key_index = 0; > + s->optcr_key_index = 0; > + > + /* Initialise register values */ > + s->flash_acr.reg = 0x00000000; > + s->flash_keyr.reg = 0x00000000; > + s->flash_optkeyr.reg = 0x00000000; > + s->flash_sr.reg = 0x00000000; > + s->flash_cr.reg = 0x80000000; > + s->flash_optcr.reg = 0x0FFFAAED; > +} > + > +static uint64_t stm32f4xx_flashif_read(void * opaque, hwaddr addr, > + unsigned int size) { > + STM32F4xxFlashIfState *s = opaque; > + > + trace_stm32f4xx_flashif_read(addr); > + > + switch (addr) { > + case FLASH_ACR: > + return s->flash_acr.reg; > + case FLASH_SR: > + return s->flash_sr.reg; > + case FLASH_CR: > + return s->flash_cr.reg; > + case FLASH_OPTCR: > + return s->flash_optcr.reg; > + default: > + qemu_log_mask( > + LOG_GUEST_ERROR, > + "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); > + return 0; > + } > +} > + > +static void flash_acr_write(STM32F4xxFlashIfState *s, FlashAcrType > +val) { > + /* Set latency */ > + s->flash_acr.latency = val.latency; > + /* Set prefetch status */ > + s->flash_acr.prften = val.prften; > + /* Set instruction cache status */ > + s->flash_acr.icen = val.icen; > + /* Set data cache status */ > + s->flash_acr.dcen = val.dcen; > +} > + > +static void flash_cr_write(STM32F4xxFlashIfState *s, FlashCrType val) > +{ > + /* Lock FLASH_CR if lock bit is set */ > + if (val.lock) { > + s->flash_cr.lock = 1; > + s->cr_key_index = 0; > + return; > + } > +} > + > +static void flash_optcr_write(STM32F4xxFlashIfState *s, > +FlashOptcrType val) { > + /* Lock FLASH_OPTCR if lock bit is set */ > + if (val.optlock) { > + s->flash_optcr.optlock = 1; > + s->optcr_key_index = 0; > + return; > + } > +} > + > +static void stm32f4xx_flashif_write(void *opaque, hwaddr addr, > + uint64_t val64, unsigned int > +size) { > + STM32F4xxFlashIfState *s = opaque; > + uint32_t value = val64; > + > + trace_stm32f4xx_flashif_write(value, addr); > + > + switch (addr) { > + case FLASH_ACR: > + flash_acr_write(s, (FlashAcrType)value); > + return; > + case FLASH_KEYR: > + if (s->cr_key_index == 0 && value == 0x45670123) { > + s->cr_key_index = 1; > + } else if (s->cr_key_index == 1 && value == 0xCDEF89AB) { > + /* Valid key; unlock FLASH_CR */ > + s->flash_cr.lock = 0; > + s->cr_key_index = 0; > + } else { > + /* Invalid key; permanently lock FLASH_CR until reset */ > + s->flash_cr.lock = 1; > + s->cr_key_index = -1; > + } > + return; > + case FLASH_OPTKEYR: > + if (s->optcr_key_index == 0 && value == 0x08192A3B) { > + s->optcr_key_index = 1; > + } else if (s->optcr_key_index == 1 && value == 0x4C5D6E7F) { > + /* Valid key; unlock FLASH_OPTCR */ > + s->flash_optcr.optlock = 0; > + s->optcr_key_index = 0; > + } else { > + /* Invalid key; lock FLASH_OPTCR until reset */ > + s->flash_optcr.optlock = 1; > + s->optcr_key_index = -1; > + } > + return; > + case FLASH_SR: > + if (s->flash_sr.eop) s->flash_sr.eop = 0; > + if (s->flash_sr.operr) s->flash_sr.operr = 0; > + if (s->flash_sr.wrperr) s->flash_sr.wrperr = 0; > + if (s->flash_sr.pgaerr) s->flash_sr.pgaerr = 0; > + if (s->flash_sr.pgperr) s->flash_sr.pgperr = 0; > + if (s->flash_sr.pgserr) s->flash_sr.pgserr = 0; > + return; > + case FLASH_CR: > + flash_cr_write(s, (FlashCrType)value); > + return; > + case FLASH_OPTCR: > + flash_optcr_write(s, (FlashOptcrType)value); > + return; > + default: > + qemu_log_mask( > + LOG_GUEST_ERROR, > + "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); > + } > +} > + > +static const MemoryRegionOps stm32f4xx_flashif_ops = { > + .read = stm32f4xx_flashif_read, > + .write = stm32f4xx_flashif_write, > + .endianness = DEVICE_NATIVE_ENDIAN }; > + > +static void stm32f4xx_flashif_init(Object *obj) { > + STM32F4xxFlashIfState *s = STM32F4XX_FLASHIF(obj); > + > + memory_region_init_io(&s->mmio, obj, &stm32f4xx_flashif_ops, s, > + TYPE_STM32F4XX_FLASHIF, 0x400); > + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); } > + > +static const VMStateDescription vmstate_stm32f4xx_flashif = { > + .name = TYPE_STM32F4XX_FLASHIF, > + .version_id = 1, > + .minimum_version_id = 1, > + .fields = (VMStateField[]) { > + VMSTATE_UINT32(flash_acr.reg, STM32F4xxFlashIfState), > + VMSTATE_UINT32(flash_keyr.reg, STM32F4xxFlashIfState), > + VMSTATE_UINT32(flash_optkeyr.reg, STM32F4xxFlashIfState), > + VMSTATE_UINT32(flash_sr.reg, STM32F4xxFlashIfState), > + VMSTATE_UINT32(flash_cr.reg, STM32F4xxFlashIfState), > + VMSTATE_UINT32(flash_optcr.reg, STM32F4xxFlashIfState), > + VMSTATE_END_OF_LIST() > + } > +}; > + > +static void stm32f4xx_flashif_class_init(ObjectClass *klass, void > +*data) { > + DeviceClass *dc = DEVICE_CLASS(klass); > + > + dc->reset = stm32f4xx_flashif_reset; > + dc->vmsd = &vmstate_stm32f4xx_flashif; } > + > +static const TypeInfo stm32f4xx_flashif_info = { > + .name = TYPE_STM32F4XX_FLASHIF, > + .parent = TYPE_SYS_BUS_DEVICE, > + .instance_size = sizeof(STM32F4xxFlashIfState), > + .instance_init = stm32f4xx_flashif_init, > + .class_init = stm32f4xx_flashif_class_init > +}; > + > +static void stm32f4xx_flashif_register_types(void) > +{ > + type_register_static(&stm32f4xx_flashif_info); > +} > + > +type_init(stm32f4xx_flashif_register_types) > diff --git a/hw/misc/trace-events b/hw/misc/trace-events index > 7f0f5dff3a..bd9a5dd483 100644 > --- a/hw/misc/trace-events > +++ b/hw/misc/trace-events > @@ -84,6 +84,10 @@ mos6522_set_sr_int(void) "set sr_int" > mos6522_write(uint64_t addr, uint64_t val) "reg=0x%"PRIx64 " > val=0x%"PRIx64 mos6522_read(uint64_t addr, unsigned val) "reg=0x%"PRIx64 " val=0x%x" > > +# stm32f4xx_flashif > +stm32f4xx_flashif_read(uint64_t addr) "reg read: addr: 0x%" PRIx64 " " > +stm32f4xx_flashif_write(uint64_t addr, uint64_t data) "reg write: addr: 0x%" PRIx64 " val: 0x%" PRIx64 "" > + > # stm32f4xx_syscfg > stm32f4xx_syscfg_set_irq(int gpio, int line, int level) "Interupt: GPIO: %d, Line: %d; Level: %d" > stm32f4xx_pulse_exti(int irq) "Pulse EXTI: %d" > diff --git a/include/hw/arm/stm32f405_soc.h > b/include/hw/arm/stm32f405_soc.h index 1fe97f8c3a..a94c3c51ac 100644 > --- a/include/hw/arm/stm32f405_soc.h > +++ b/include/hw/arm/stm32f405_soc.h > @@ -25,6 +25,7 @@ > #ifndef HW_ARM_STM32F405_SOC_H > #define HW_ARM_STM32F405_SOC_H > > +#include "hw/misc/stm32f4xx_flashif.h" > #include "hw/misc/stm32f4xx_syscfg.h" > #include "hw/timer/stm32f2xx_timer.h" > #include "hw/char/stm32f2xx_usart.h" > @@ -57,6 +58,7 @@ typedef struct STM32F405State { > > ARMv7MState armv7m; > > + STM32F4xxFlashIfState flashif; > STM32F4xxSyscfgState syscfg; > STM32F4xxExtiState exti; > STM32F2XXUsartState usart[STM_NUM_USARTS]; diff --git > a/include/hw/misc/stm32f4xx_flashif.h > b/include/hw/misc/stm32f4xx_flashif.h > new file mode 100644 > index 0000000000..e364ca39c7 > --- /dev/null > +++ b/include/hw/misc/stm32f4xx_flashif.h > @@ -0,0 +1,144 @@ > +/* > + * STM32F4xx FLASHIF > + * > + * Copyright (c) 2020 Stephanos Ioannidis <root@stephanos.io> > + * > + * Permission is hereby granted, free of charge, to any person > +obtaining a copy > + * of this software and associated documentation files (the > +"Software"), to deal > + * in the Software without restriction, including without limitation > +the rights > + * to use, copy, modify, merge, publish, distribute, sublicense, > +and/or sell > + * copies of the Software, and to permit persons to whom the Software > +is > + * furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice shall be > +included in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, > +EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF > +MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT > +SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES > +OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, > +ARISING FROM, > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER > +DEALINGS IN > + * THE SOFTWARE. > + */ > + > +#ifndef HW_STM_FLASHIF_H > +#define HW_STM_FLASHIF_H > + > +#include "hw/sysbus.h" > +#include "hw/hw.h" > + > +#define TYPE_STM32F4XX_FLASHIF "stm32f4xx-flashif" > +#define STM32F4XX_FLASHIF(obj) \ > + OBJECT_CHECK(STM32F4xxFlashIfState, (obj), > +TYPE_STM32F4XX_FLASHIF) > + > +#define FLASH_ACR 0x00 > +#define FLASH_KEYR 0x04 > +#define FLASH_OPTKEYR 0x08 > +#define FLASH_SR 0x0C > +#define FLASH_CR 0x10 > +#define FLASH_OPTCR 0x14 > + > +typedef union { > + struct { > + uint32_t latency : 3; > + uint32_t reserved0 : 5; > + uint32_t prften : 1; > + uint32_t icen : 1; > + uint32_t dcen : 1; > + uint32_t icrst : 1; > + uint32_t dcrst : 1; > + uint32_t reserved1 : 19; > + }; > + uint32_t reg; > +} FlashAcrType; > + > +typedef union { > + struct { > + uint32_t key : 32; > + }; > + uint32_t reg; > +} FlashKeyrType; > + > +typedef union { > + struct { > + uint32_t optkey : 32; > + }; > + uint32_t reg; > +} FlashOptkeyrType; > + > +typedef union { > + struct { > + uint32_t eop : 1; > + uint32_t operr : 1; > + uint32_t reserved0 : 2; > + uint32_t wrperr : 1; > + uint32_t pgaerr : 1; > + uint32_t pgperr : 1; > + uint32_t pgserr : 1; > + uint32_t reserved1 : 8; > + uint32_t bsy : 1; > + uint32_t reserved2 : 15; > + }; > + uint32_t reg; > +} FlashSrType; > + > +typedef union { > + struct { > + uint32_t pg : 1; > + uint32_t ser : 1; > + uint32_t mer : 1; > + uint32_t snb : 4; > + uint32_t reserved0 : 1; > + uint32_t psize : 2; > + uint32_t reserved1 : 6; > + uint32_t strt : 1; > + uint32_t reserved2 : 7; > + uint32_t eopie : 1; > + uint32_t reserved3 : 6; > + uint32_t lock : 1; > + }; > + uint32_t reg; > +} FlashCrType; > + > +typedef union { > + struct { > + uint32_t optlock : 1; > + uint32_t optstrt : 1; > + uint32_t bor_lev : 2; > + uint32_t reserved0 : 1; > + uint32_t wdg_sw : 1; > + uint32_t nrst_stop : 1; > + uint32_t nrst_stdby : 1; > + uint32_t rdp : 8; > + uint32_t nwrp : 12; > + uint32_t reserved1 : 4; > + }; > + uint32_t reg; > +} FlashOptcrType; > + > +typedef struct { > + /* <private> */ > + SysBusDevice parent_obj; > + > + /* <public> */ > + MemoryRegion mmio; > + > + int32_t cr_key_index; > + int32_t optcr_key_index; > + > + /* Access control register (FLASH_ACR) */ > + FlashAcrType flash_acr; > + /* Key register (FLASH_KEYR) */ > + FlashKeyrType flash_keyr; > + /* Option key register (FLASH_OPTKEYR) */ > + FlashOptkeyrType flash_optkeyr; > + /* Status register (FLASH_SR) */ > + FlashSrType flash_sr; > + /* Control register (FLASH_CR) */ > + FlashCrType flash_cr; > + /* Option control register (FLASH_OPTCR) */ > + FlashOptcrType flash_optcr; > +} STM32F4xxFlashIfState; > + > +#endif > -- > 2.17.1 > >
On 3/1/20 9:45 AM, Stephanos Ioannidis wrote: > The flash interface (FLASHIF) peripheral provides a control interface > for the SoC embedded flash memory on the STM32F4xx series devices. > > This commit adds preliminary support for the flash interface peripheral > emulation, in order to support proper emulation of the firmware images > that use the STM32Cube driver, which configures and validates the > FLASH_ACR register during system initialisation. > > Signed-off-by: Stephanos Ioannidis <root@stephanos.io> > --- > hw/arm/Kconfig | 1 + > hw/arm/stm32f405_soc.c | 15 +- > hw/misc/Kconfig | 3 + > hw/misc/Makefile.objs | 1 + > hw/misc/stm32f4xx_flashif.c | 215 ++++++++++++++++++++++++++++ > hw/misc/trace-events | 4 + > include/hw/arm/stm32f405_soc.h | 2 + > include/hw/misc/stm32f4xx_flashif.h | 144 +++++++++++++++++++ Consider using the scripts/git.orderfile configuration. > 8 files changed, 384 insertions(+), 1 deletion(-) > create mode 100644 hw/misc/stm32f4xx_flashif.c > create mode 100644 include/hw/misc/stm32f4xx_flashif.h > > diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig > index 3d86691ae0..179696ec91 100644 > --- a/hw/arm/Kconfig > +++ b/hw/arm/Kconfig > @@ -314,6 +314,7 @@ config STM32F205_SOC > config STM32F405_SOC > bool > select ARM_V7M > + select STM32F4XX_FLASHIF > select STM32F4XX_SYSCFG > select STM32F4XX_EXTI > > diff --git a/hw/arm/stm32f405_soc.c b/hw/arm/stm32f405_soc.c > index 9bcad97853..72b16910c7 100644 > --- a/hw/arm/stm32f405_soc.c > +++ b/hw/arm/stm32f405_soc.c > @@ -30,6 +30,7 @@ > #include "hw/arm/stm32f405_soc.h" > #include "hw/misc/unimp.h" > > +#define FLASHIF_ADDR 0x40023C00 > #define SYSCFG_ADD 0x40013800 > static const uint32_t usart_addr[] = { 0x40011000, 0x40004400, 0x40004800, > 0x40004C00, 0x40005000, 0x40011400, > @@ -59,6 +60,9 @@ static void stm32f405_soc_initfn(Object *obj) > sysbus_init_child_obj(obj, "armv7m", &s->armv7m, sizeof(s->armv7m), > TYPE_ARMV7M); > > + sysbus_init_child_obj(obj, "flashif", &s->flashif, sizeof(s->flashif), > + TYPE_STM32F4XX_FLASHIF); > + > sysbus_init_child_obj(obj, "syscfg", &s->syscfg, sizeof(s->syscfg), > TYPE_STM32F4XX_SYSCFG); > > @@ -130,6 +134,16 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) > return; > } > > + /* Flash interface */ > + dev = DEVICE(&s->flashif); You might want to add a 'link property' to the s->flash memory region here, so you can lock/unlock/program/fuse it later. > + object_property_set_bool(OBJECT(&s->flashif), true, "realized", &err); > + if (err != NULL) { > + error_propagate(errp, err); > + return; > + } > + busdev = SYS_BUS_DEVICE(dev); > + sysbus_mmio_map(busdev, 0, FLASHIF_ADDR); > + > /* System configuration controller */ > dev = DEVICE(&s->syscfg); > object_property_set_bool(OBJECT(&s->syscfg), true, "realized", &err); > @@ -261,7 +275,6 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) > create_unimplemented_device("GPIOI", 0x40022000, 0x400); > create_unimplemented_device("CRC", 0x40023000, 0x400); > create_unimplemented_device("RCC", 0x40023800, 0x400); > - create_unimplemented_device("Flash Int", 0x40023C00, 0x400); > create_unimplemented_device("BKPSRAM", 0x40024000, 0x400); > create_unimplemented_device("DMA1", 0x40026000, 0x400); > create_unimplemented_device("DMA2", 0x40026400, 0x400); [...]
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 3d86691ae0..179696ec91 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -314,6 +314,7 @@ config STM32F205_SOC config STM32F405_SOC bool select ARM_V7M + select STM32F4XX_FLASHIF select STM32F4XX_SYSCFG select STM32F4XX_EXTI diff --git a/hw/arm/stm32f405_soc.c b/hw/arm/stm32f405_soc.c index 9bcad97853..72b16910c7 100644 --- a/hw/arm/stm32f405_soc.c +++ b/hw/arm/stm32f405_soc.c @@ -30,6 +30,7 @@ #include "hw/arm/stm32f405_soc.h" #include "hw/misc/unimp.h" +#define FLASHIF_ADDR 0x40023C00 #define SYSCFG_ADD 0x40013800 static const uint32_t usart_addr[] = { 0x40011000, 0x40004400, 0x40004800, 0x40004C00, 0x40005000, 0x40011400, @@ -59,6 +60,9 @@ static void stm32f405_soc_initfn(Object *obj) sysbus_init_child_obj(obj, "armv7m", &s->armv7m, sizeof(s->armv7m), TYPE_ARMV7M); + sysbus_init_child_obj(obj, "flashif", &s->flashif, sizeof(s->flashif), + TYPE_STM32F4XX_FLASHIF); + sysbus_init_child_obj(obj, "syscfg", &s->syscfg, sizeof(s->syscfg), TYPE_STM32F4XX_SYSCFG); @@ -130,6 +134,16 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) return; } + /* Flash interface */ + dev = DEVICE(&s->flashif); + object_property_set_bool(OBJECT(&s->flashif), true, "realized", &err); + if (err != NULL) { + error_propagate(errp, err); + return; + } + busdev = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(busdev, 0, FLASHIF_ADDR); + /* System configuration controller */ dev = DEVICE(&s->syscfg); object_property_set_bool(OBJECT(&s->syscfg), true, "realized", &err); @@ -261,7 +275,6 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) create_unimplemented_device("GPIOI", 0x40022000, 0x400); create_unimplemented_device("CRC", 0x40023000, 0x400); create_unimplemented_device("RCC", 0x40023800, 0x400); - create_unimplemented_device("Flash Int", 0x40023C00, 0x400); create_unimplemented_device("BKPSRAM", 0x40024000, 0x400); create_unimplemented_device("DMA1", 0x40026000, 0x400); create_unimplemented_device("DMA2", 0x40026400, 0x400); diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index bdd77d8020..e333a955b2 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -79,6 +79,9 @@ config IMX select SSI select USB_EHCI_SYSBUS +config STM32F4XX_FLASHIF + bool + config STM32F2XX_SYSCFG bool diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index da993f45b7..1aea0b9bb9 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -58,6 +58,7 @@ 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 +common-obj-$(CONFIG_STM32F4XX_FLASHIF) += stm32f4xx_flashif.o common-obj-$(CONFIG_STM32F2XX_SYSCFG) += stm32f2xx_syscfg.o common-obj-$(CONFIG_STM32F4XX_SYSCFG) += stm32f4xx_syscfg.o common-obj-$(CONFIG_STM32F4XX_EXTI) += stm32f4xx_exti.o diff --git a/hw/misc/stm32f4xx_flashif.c b/hw/misc/stm32f4xx_flashif.c new file mode 100644 index 0000000000..d280fc5b2c --- /dev/null +++ b/hw/misc/stm32f4xx_flashif.c @@ -0,0 +1,215 @@ +/* + * STM32F4xx FLASHIF + * + * Copyright (c) 2020 Stephanos Ioannidis <root@stephanos.io> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "trace.h" +#include "hw/irq.h" +#include "migration/vmstate.h" +#include "hw/misc/stm32f4xx_flashif.h" + +static void stm32f4xx_flashif_reset(DeviceState *dev) +{ + STM32F4xxFlashIfState *s = STM32F4XX_FLASHIF(dev); + + /* Initialise states */ + s->cr_key_index = 0; + s->optcr_key_index = 0; + + /* Initialise register values */ + s->flash_acr.reg = 0x00000000; + s->flash_keyr.reg = 0x00000000; + s->flash_optkeyr.reg = 0x00000000; + s->flash_sr.reg = 0x00000000; + s->flash_cr.reg = 0x80000000; + s->flash_optcr.reg = 0x0FFFAAED; +} + +static uint64_t stm32f4xx_flashif_read(void * opaque, hwaddr addr, + unsigned int size) +{ + STM32F4xxFlashIfState *s = opaque; + + trace_stm32f4xx_flashif_read(addr); + + switch (addr) { + case FLASH_ACR: + return s->flash_acr.reg; + case FLASH_SR: + return s->flash_sr.reg; + case FLASH_CR: + return s->flash_cr.reg; + case FLASH_OPTCR: + return s->flash_optcr.reg; + default: + qemu_log_mask( + LOG_GUEST_ERROR, + "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); + return 0; + } +} + +static void flash_acr_write(STM32F4xxFlashIfState *s, FlashAcrType val) +{ + /* Set latency */ + s->flash_acr.latency = val.latency; + /* Set prefetch status */ + s->flash_acr.prften = val.prften; + /* Set instruction cache status */ + s->flash_acr.icen = val.icen; + /* Set data cache status */ + s->flash_acr.dcen = val.dcen; +} + +static void flash_cr_write(STM32F4xxFlashIfState *s, FlashCrType val) +{ + /* Lock FLASH_CR if lock bit is set */ + if (val.lock) { + s->flash_cr.lock = 1; + s->cr_key_index = 0; + return; + } +} + +static void flash_optcr_write(STM32F4xxFlashIfState *s, FlashOptcrType val) +{ + /* Lock FLASH_OPTCR if lock bit is set */ + if (val.optlock) { + s->flash_optcr.optlock = 1; + s->optcr_key_index = 0; + return; + } +} + +static void stm32f4xx_flashif_write(void *opaque, hwaddr addr, + uint64_t val64, unsigned int size) +{ + STM32F4xxFlashIfState *s = opaque; + uint32_t value = val64; + + trace_stm32f4xx_flashif_write(value, addr); + + switch (addr) { + case FLASH_ACR: + flash_acr_write(s, (FlashAcrType)value); + return; + case FLASH_KEYR: + if (s->cr_key_index == 0 && value == 0x45670123) { + s->cr_key_index = 1; + } else if (s->cr_key_index == 1 && value == 0xCDEF89AB) { + /* Valid key; unlock FLASH_CR */ + s->flash_cr.lock = 0; + s->cr_key_index = 0; + } else { + /* Invalid key; permanently lock FLASH_CR until reset */ + s->flash_cr.lock = 1; + s->cr_key_index = -1; + } + return; + case FLASH_OPTKEYR: + if (s->optcr_key_index == 0 && value == 0x08192A3B) { + s->optcr_key_index = 1; + } else if (s->optcr_key_index == 1 && value == 0x4C5D6E7F) { + /* Valid key; unlock FLASH_OPTCR */ + s->flash_optcr.optlock = 0; + s->optcr_key_index = 0; + } else { + /* Invalid key; lock FLASH_OPTCR until reset */ + s->flash_optcr.optlock = 1; + s->optcr_key_index = -1; + } + return; + case FLASH_SR: + if (s->flash_sr.eop) s->flash_sr.eop = 0; + if (s->flash_sr.operr) s->flash_sr.operr = 0; + if (s->flash_sr.wrperr) s->flash_sr.wrperr = 0; + if (s->flash_sr.pgaerr) s->flash_sr.pgaerr = 0; + if (s->flash_sr.pgperr) s->flash_sr.pgperr = 0; + if (s->flash_sr.pgserr) s->flash_sr.pgserr = 0; + return; + case FLASH_CR: + flash_cr_write(s, (FlashCrType)value); + return; + case FLASH_OPTCR: + flash_optcr_write(s, (FlashOptcrType)value); + return; + default: + qemu_log_mask( + LOG_GUEST_ERROR, + "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); + } +} + +static const MemoryRegionOps stm32f4xx_flashif_ops = { + .read = stm32f4xx_flashif_read, + .write = stm32f4xx_flashif_write, + .endianness = DEVICE_NATIVE_ENDIAN +}; + +static void stm32f4xx_flashif_init(Object *obj) +{ + STM32F4xxFlashIfState *s = STM32F4XX_FLASHIF(obj); + + memory_region_init_io(&s->mmio, obj, &stm32f4xx_flashif_ops, s, + TYPE_STM32F4XX_FLASHIF, 0x400); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); +} + +static const VMStateDescription vmstate_stm32f4xx_flashif = { + .name = TYPE_STM32F4XX_FLASHIF, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(flash_acr.reg, STM32F4xxFlashIfState), + VMSTATE_UINT32(flash_keyr.reg, STM32F4xxFlashIfState), + VMSTATE_UINT32(flash_optkeyr.reg, STM32F4xxFlashIfState), + VMSTATE_UINT32(flash_sr.reg, STM32F4xxFlashIfState), + VMSTATE_UINT32(flash_cr.reg, STM32F4xxFlashIfState), + VMSTATE_UINT32(flash_optcr.reg, STM32F4xxFlashIfState), + VMSTATE_END_OF_LIST() + } +}; + +static void stm32f4xx_flashif_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = stm32f4xx_flashif_reset; + dc->vmsd = &vmstate_stm32f4xx_flashif; +} + +static const TypeInfo stm32f4xx_flashif_info = { + .name = TYPE_STM32F4XX_FLASHIF, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(STM32F4xxFlashIfState), + .instance_init = stm32f4xx_flashif_init, + .class_init = stm32f4xx_flashif_class_init +}; + +static void stm32f4xx_flashif_register_types(void) +{ + type_register_static(&stm32f4xx_flashif_info); +} + +type_init(stm32f4xx_flashif_register_types) diff --git a/hw/misc/trace-events b/hw/misc/trace-events index 7f0f5dff3a..bd9a5dd483 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -84,6 +84,10 @@ mos6522_set_sr_int(void) "set sr_int" mos6522_write(uint64_t addr, uint64_t val) "reg=0x%"PRIx64 " val=0x%"PRIx64 mos6522_read(uint64_t addr, unsigned val) "reg=0x%"PRIx64 " val=0x%x" +# stm32f4xx_flashif +stm32f4xx_flashif_read(uint64_t addr) "reg read: addr: 0x%" PRIx64 " " +stm32f4xx_flashif_write(uint64_t addr, uint64_t data) "reg write: addr: 0x%" PRIx64 " val: 0x%" PRIx64 "" + # stm32f4xx_syscfg stm32f4xx_syscfg_set_irq(int gpio, int line, int level) "Interupt: GPIO: %d, Line: %d; Level: %d" stm32f4xx_pulse_exti(int irq) "Pulse EXTI: %d" diff --git a/include/hw/arm/stm32f405_soc.h b/include/hw/arm/stm32f405_soc.h index 1fe97f8c3a..a94c3c51ac 100644 --- a/include/hw/arm/stm32f405_soc.h +++ b/include/hw/arm/stm32f405_soc.h @@ -25,6 +25,7 @@ #ifndef HW_ARM_STM32F405_SOC_H #define HW_ARM_STM32F405_SOC_H +#include "hw/misc/stm32f4xx_flashif.h" #include "hw/misc/stm32f4xx_syscfg.h" #include "hw/timer/stm32f2xx_timer.h" #include "hw/char/stm32f2xx_usart.h" @@ -57,6 +58,7 @@ typedef struct STM32F405State { ARMv7MState armv7m; + STM32F4xxFlashIfState flashif; STM32F4xxSyscfgState syscfg; STM32F4xxExtiState exti; STM32F2XXUsartState usart[STM_NUM_USARTS]; diff --git a/include/hw/misc/stm32f4xx_flashif.h b/include/hw/misc/stm32f4xx_flashif.h new file mode 100644 index 0000000000..e364ca39c7 --- /dev/null +++ b/include/hw/misc/stm32f4xx_flashif.h @@ -0,0 +1,144 @@ +/* + * STM32F4xx FLASHIF + * + * Copyright (c) 2020 Stephanos Ioannidis <root@stephanos.io> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_STM_FLASHIF_H +#define HW_STM_FLASHIF_H + +#include "hw/sysbus.h" +#include "hw/hw.h" + +#define TYPE_STM32F4XX_FLASHIF "stm32f4xx-flashif" +#define STM32F4XX_FLASHIF(obj) \ + OBJECT_CHECK(STM32F4xxFlashIfState, (obj), TYPE_STM32F4XX_FLASHIF) + +#define FLASH_ACR 0x00 +#define FLASH_KEYR 0x04 +#define FLASH_OPTKEYR 0x08 +#define FLASH_SR 0x0C +#define FLASH_CR 0x10 +#define FLASH_OPTCR 0x14 + +typedef union { + struct { + uint32_t latency : 3; + uint32_t reserved0 : 5; + uint32_t prften : 1; + uint32_t icen : 1; + uint32_t dcen : 1; + uint32_t icrst : 1; + uint32_t dcrst : 1; + uint32_t reserved1 : 19; + }; + uint32_t reg; +} FlashAcrType; + +typedef union { + struct { + uint32_t key : 32; + }; + uint32_t reg; +} FlashKeyrType; + +typedef union { + struct { + uint32_t optkey : 32; + }; + uint32_t reg; +} FlashOptkeyrType; + +typedef union { + struct { + uint32_t eop : 1; + uint32_t operr : 1; + uint32_t reserved0 : 2; + uint32_t wrperr : 1; + uint32_t pgaerr : 1; + uint32_t pgperr : 1; + uint32_t pgserr : 1; + uint32_t reserved1 : 8; + uint32_t bsy : 1; + uint32_t reserved2 : 15; + }; + uint32_t reg; +} FlashSrType; + +typedef union { + struct { + uint32_t pg : 1; + uint32_t ser : 1; + uint32_t mer : 1; + uint32_t snb : 4; + uint32_t reserved0 : 1; + uint32_t psize : 2; + uint32_t reserved1 : 6; + uint32_t strt : 1; + uint32_t reserved2 : 7; + uint32_t eopie : 1; + uint32_t reserved3 : 6; + uint32_t lock : 1; + }; + uint32_t reg; +} FlashCrType; + +typedef union { + struct { + uint32_t optlock : 1; + uint32_t optstrt : 1; + uint32_t bor_lev : 2; + uint32_t reserved0 : 1; + uint32_t wdg_sw : 1; + uint32_t nrst_stop : 1; + uint32_t nrst_stdby : 1; + uint32_t rdp : 8; + uint32_t nwrp : 12; + uint32_t reserved1 : 4; + }; + uint32_t reg; +} FlashOptcrType; + +typedef struct { + /* <private> */ + SysBusDevice parent_obj; + + /* <public> */ + MemoryRegion mmio; + + int32_t cr_key_index; + int32_t optcr_key_index; + + /* Access control register (FLASH_ACR) */ + FlashAcrType flash_acr; + /* Key register (FLASH_KEYR) */ + FlashKeyrType flash_keyr; + /* Option key register (FLASH_OPTKEYR) */ + FlashOptkeyrType flash_optkeyr; + /* Status register (FLASH_SR) */ + FlashSrType flash_sr; + /* Control register (FLASH_CR) */ + FlashCrType flash_cr; + /* Option control register (FLASH_OPTCR) */ + FlashOptcrType flash_optcr; +} STM32F4xxFlashIfState; + +#endif
The flash interface (FLASHIF) peripheral provides a control interface for the SoC embedded flash memory on the STM32F4xx series devices. This commit adds preliminary support for the flash interface peripheral emulation, in order to support proper emulation of the firmware images that use the STM32Cube driver, which configures and validates the FLASH_ACR register during system initialisation. Signed-off-by: Stephanos Ioannidis <root@stephanos.io> --- hw/arm/Kconfig | 1 + hw/arm/stm32f405_soc.c | 15 +- hw/misc/Kconfig | 3 + hw/misc/Makefile.objs | 1 + hw/misc/stm32f4xx_flashif.c | 215 ++++++++++++++++++++++++++++ hw/misc/trace-events | 4 + include/hw/arm/stm32f405_soc.h | 2 + include/hw/misc/stm32f4xx_flashif.h | 144 +++++++++++++++++++ 8 files changed, 384 insertions(+), 1 deletion(-) create mode 100644 hw/misc/stm32f4xx_flashif.c create mode 100644 include/hw/misc/stm32f4xx_flashif.h