diff options
Diffstat (limited to 'hw')
92 files changed, 1322 insertions, 186 deletions
diff --git a/hw/adc/npcm7xx_adc.c b/hw/adc/npcm7xx_adc.c index c6647ee..de8469d 100644 --- a/hw/adc/npcm7xx_adc.c +++ b/hw/adc/npcm7xx_adc.c @@ -218,7 +218,7 @@ static void npcm7xx_adc_enter_reset(Object *obj, ResetType type) npcm7xx_adc_reset(s); } -static void npcm7xx_adc_hold_reset(Object *obj) +static void npcm7xx_adc_hold_reset(Object *obj, ResetType type) { NPCM7xxADCState *s = NPCM7XX_ADC(obj); diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 893a7bf..098d043 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -477,6 +477,7 @@ config STM32L4X5_SOC select STM32L4X5_SYSCFG select STM32L4X5_RCC select STM32L4X5_GPIO + select STM32L4X5_USART config XLNX_ZYNQMP_ARM bool diff --git a/hw/arm/pxa2xx_pic.c b/hw/arm/pxa2xx_pic.c index f54546c..34c5555 100644 --- a/hw/arm/pxa2xx_pic.c +++ b/hw/arm/pxa2xx_pic.c @@ -272,7 +272,7 @@ static int pxa2xx_pic_post_load(void *opaque, int version_id) return 0; } -static void pxa2xx_pic_reset_hold(Object *obj) +static void pxa2xx_pic_reset_hold(Object *obj, ResetType type) { PXA2xxPICState *s = PXA2XX_PIC(obj); diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c index c4b5406..1ce706b 100644 --- a/hw/arm/smmu-common.c +++ b/hw/arm/smmu-common.c @@ -682,7 +682,7 @@ static void smmu_base_realize(DeviceState *dev, Error **errp) } } -static void smmu_base_reset_hold(Object *obj) +static void smmu_base_reset_hold(Object *obj, ResetType type) { SMMUState *s = ARM_SMMU(obj); diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index 9eb56a7..2d1e0d5 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -1727,13 +1727,13 @@ static void smmu_init_irq(SMMUv3State *s, SysBusDevice *dev) } } -static void smmu_reset_hold(Object *obj) +static void smmu_reset_hold(Object *obj, ResetType type) { SMMUv3State *s = ARM_SMMUV3(obj); SMMUv3Class *c = ARM_SMMUV3_GET_CLASS(s); if (c->parent_phases.hold) { - c->parent_phases.hold(obj); + c->parent_phases.hold(obj, type); } smmuv3_init_regs(s); diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c index a2f998b..3767462 100644 --- a/hw/arm/stellaris.c +++ b/hw/arm/stellaris.c @@ -394,7 +394,7 @@ static void stellaris_sys_reset_enter(Object *obj, ResetType type) s->dcgc[0] = 1; } -static void stellaris_sys_reset_hold(Object *obj) +static void stellaris_sys_reset_hold(Object *obj, ResetType type) { ssys_state *s = STELLARIS_SYS(obj); @@ -402,7 +402,7 @@ static void stellaris_sys_reset_hold(Object *obj) ssys_calculate_system_clock(s, true); } -static void stellaris_sys_reset_exit(Object *obj) +static void stellaris_sys_reset_exit(Object *obj, ResetType type) { } @@ -618,7 +618,7 @@ static void stellaris_i2c_reset_enter(Object *obj, ResetType type) i2c_end_transfer(s->bus); } -static void stellaris_i2c_reset_hold(Object *obj) +static void stellaris_i2c_reset_hold(Object *obj, ResetType type) { stellaris_i2c_state *s = STELLARIS_I2C(obj); @@ -631,7 +631,7 @@ static void stellaris_i2c_reset_hold(Object *obj) s->mcr = 0; } -static void stellaris_i2c_reset_exit(Object *obj) +static void stellaris_i2c_reset_exit(Object *obj, ResetType type) { stellaris_i2c_state *s = STELLARIS_I2C(obj); @@ -787,7 +787,7 @@ static void stellaris_adc_trigger(void *opaque, int irq, int level) } } -static void stellaris_adc_reset_hold(Object *obj) +static void stellaris_adc_reset_hold(Object *obj, ResetType type) { StellarisADCState *s = STELLARIS_ADC(obj); int n; diff --git a/hw/arm/stm32l4x5_soc.c b/hw/arm/stm32l4x5_soc.c index 40e294f..3992482 100644 --- a/hw/arm/stm32l4x5_soc.c +++ b/hw/arm/stm32l4x5_soc.c @@ -28,6 +28,7 @@ #include "sysemu/sysemu.h" #include "hw/or-irq.h" #include "hw/arm/stm32l4x5_soc.h" +#include "hw/char/stm32l4x5_usart.h" #include "hw/gpio/stm32l4x5_gpio.h" #include "hw/qdev-clock.h" #include "hw/misc/unimp.h" @@ -116,6 +117,22 @@ static const struct { { 0x48001C00, 0x0000000F, 0x00000000, 0x00000000 }, }; +static const hwaddr usart_addr[] = { + 0x40013800, /* "USART1", 0x400 */ + 0x40004400, /* "USART2", 0x400 */ + 0x40004800, /* "USART3", 0x400 */ +}; +static const hwaddr uart_addr[] = { + 0x40004C00, /* "UART4" , 0x400 */ + 0x40005000 /* "UART5" , 0x400 */ +}; + +#define LPUART_BASE_ADDRESS 0x40008000 + +static const int usart_irq[] = { 37, 38, 39 }; +static const int uart_irq[] = { 52, 53 }; +#define LPUART_IRQ 70 + static void stm32l4x5_soc_initfn(Object *obj) { Stm32l4x5SocState *s = STM32L4X5_SOC(obj); @@ -132,6 +149,18 @@ static void stm32l4x5_soc_initfn(Object *obj) g_autofree char *name = g_strdup_printf("gpio%c", 'a' + i); object_initialize_child(obj, name, &s->gpio[i], TYPE_STM32L4X5_GPIO); } + + for (int i = 0; i < STM_NUM_USARTS; i++) { + object_initialize_child(obj, "usart[*]", &s->usart[i], + TYPE_STM32L4X5_USART); + } + + for (int i = 0; i < STM_NUM_UARTS; i++) { + object_initialize_child(obj, "uart[*]", &s->uart[i], + TYPE_STM32L4X5_UART); + } + object_initialize_child(obj, "lpuart1", &s->lpuart, + TYPE_STM32L4X5_LPUART); } static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp) @@ -279,6 +308,54 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp) sysbus_mmio_map(busdev, 0, RCC_BASE_ADDRESS); sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, RCC_IRQ)); + /* USART devices */ + for (int i = 0; i < STM_NUM_USARTS; i++) { + g_autofree char *name = g_strdup_printf("usart%d-out", i + 1); + dev = DEVICE(&(s->usart[i])); + qdev_prop_set_chr(dev, "chardev", serial_hd(i)); + qdev_connect_clock_in(dev, "clk", + qdev_get_clock_out(DEVICE(&(s->rcc)), name)); + busdev = SYS_BUS_DEVICE(dev); + if (!sysbus_realize(busdev, errp)) { + return; + } + sysbus_mmio_map(busdev, 0, usart_addr[i]); + sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, usart_irq[i])); + } + + /* + * TODO: Connect the USARTs, UARTs and LPUART to the EXTI once the EXTI + * can handle other gpio-in than the gpios. (e.g. Direct Lines for the + * usarts) + */ + + /* UART devices */ + for (int i = 0; i < STM_NUM_UARTS; i++) { + g_autofree char *name = g_strdup_printf("uart%d-out", STM_NUM_USARTS + i + 1); + dev = DEVICE(&(s->uart[i])); + qdev_prop_set_chr(dev, "chardev", serial_hd(STM_NUM_USARTS + i)); + qdev_connect_clock_in(dev, "clk", + qdev_get_clock_out(DEVICE(&(s->rcc)), name)); + busdev = SYS_BUS_DEVICE(dev); + if (!sysbus_realize(busdev, errp)) { + return; + } + sysbus_mmio_map(busdev, 0, uart_addr[i]); + sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, uart_irq[i])); + } + + /* LPUART device*/ + dev = DEVICE(&(s->lpuart)); + qdev_prop_set_chr(dev, "chardev", serial_hd(STM_NUM_USARTS + STM_NUM_UARTS)); + qdev_connect_clock_in(dev, "clk", + qdev_get_clock_out(DEVICE(&(s->rcc)), "lpuart1-out")); + busdev = SYS_BUS_DEVICE(dev); + if (!sysbus_realize(busdev, errp)) { + return; + } + sysbus_mmio_map(busdev, 0, LPUART_BASE_ADDRESS); + sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, LPUART_IRQ)); + /* APB1 BUS */ create_unimplemented_device("TIM2", 0x40000000, 0x400); create_unimplemented_device("TIM3", 0x40000400, 0x400); @@ -294,10 +371,6 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp) create_unimplemented_device("SPI2", 0x40003800, 0x400); create_unimplemented_device("SPI3", 0x40003C00, 0x400); /* RESERVED: 0x40004000, 0x400 */ - create_unimplemented_device("USART2", 0x40004400, 0x400); - create_unimplemented_device("USART3", 0x40004800, 0x400); - create_unimplemented_device("UART4", 0x40004C00, 0x400); - create_unimplemented_device("UART5", 0x40005000, 0x400); create_unimplemented_device("I2C1", 0x40005400, 0x400); create_unimplemented_device("I2C2", 0x40005800, 0x400); create_unimplemented_device("I2C3", 0x40005C00, 0x400); @@ -308,7 +381,6 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp) create_unimplemented_device("DAC1", 0x40007400, 0x400); create_unimplemented_device("OPAMP", 0x40007800, 0x400); create_unimplemented_device("LPTIM1", 0x40007C00, 0x400); - create_unimplemented_device("LPUART1", 0x40008000, 0x400); /* RESERVED: 0x40008400, 0x400 */ create_unimplemented_device("SWPMI1", 0x40008800, 0x400); /* RESERVED: 0x40008C00, 0x800 */ @@ -325,7 +397,6 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp) create_unimplemented_device("TIM1", 0x40012C00, 0x400); create_unimplemented_device("SPI1", 0x40013000, 0x400); create_unimplemented_device("TIM8", 0x40013400, 0x400); - create_unimplemented_device("USART1", 0x40013800, 0x400); /* RESERVED: 0x40013C00, 0x400 */ create_unimplemented_device("TIM15", 0x40014000, 0x400); create_unimplemented_device("TIM16", 0x40014400, 0x400); diff --git a/hw/arm/virt.c b/hw/arm/virt.c index c9119ef..3c93c0c 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -729,6 +729,20 @@ static void create_v2m(VirtMachineState *vms) vms->msi_controller = VIRT_MSI_CTRL_GICV2M; } +/* + * If the CPU has FEAT_NMI, then turn on the NMI support in the GICv3 too. + * It's permitted to have a configuration with NMI in the CPU (and thus the + * GICv3 CPU interface) but not in the distributor/redistributors, but it's + * not very useful. + */ +static bool gicv3_nmi_present(VirtMachineState *vms) +{ + ARMCPU *cpu = ARM_CPU(qemu_get_cpu(0)); + + return tcg_enabled() && cpu_isar_feature(aa64_nmi, cpu) && + (vms->gic_version != VIRT_GIC_VERSION_2); +} + static void create_gic(VirtMachineState *vms, MemoryRegion *mem) { MachineState *ms = MACHINE(vms); @@ -802,6 +816,11 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem) vms->virt); } } + + if (gicv3_nmi_present(vms)) { + qdev_prop_set_bit(vms->gic, "has-nmi", true); + } + gicbusdev = SYS_BUS_DEVICE(vms->gic); sysbus_realize_and_unref(gicbusdev, &error_fatal); sysbus_mmio_map(gicbusdev, 0, vms->memmap[VIRT_GIC_DIST].base); @@ -821,7 +840,8 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem) /* Wire the outputs from each CPU's generic timer and the GICv3 * maintenance interrupt signal to the appropriate GIC PPI inputs, - * and the GIC's IRQ/FIQ/VIRQ/VFIQ interrupt outputs to the CPU's inputs. + * and the GIC's IRQ/FIQ/VIRQ/VFIQ/NMI/VINMI interrupt outputs to the + * CPU's inputs. */ for (i = 0; i < smp_cpus; i++) { DeviceState *cpudev = DEVICE(qemu_get_cpu(i)); @@ -865,6 +885,13 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem) qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ)); sysbus_connect_irq(gicbusdev, i + 3 * smp_cpus, qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ)); + + if (vms->gic_version != VIRT_GIC_VERSION_2) { + sysbus_connect_irq(gicbusdev, i + 4 * smp_cpus, + qdev_get_gpio_in(cpudev, ARM_CPU_NMI)); + sysbus_connect_irq(gicbusdev, i + 5 * smp_cpus, + qdev_get_gpio_in(cpudev, ARM_CPU_VINMI)); + } } fdt_add_gic_node(vms); diff --git a/hw/audio/asc.c b/hw/audio/asc.c index 87b5624..8054163 100644 --- a/hw/audio/asc.c +++ b/hw/audio/asc.c @@ -610,7 +610,7 @@ static void asc_fifo_init(ASCFIFOState *fs, int index) g_free(name); } -static void asc_reset_hold(Object *obj) +static void asc_reset_hold(Object *obj, ResetType type) { ASCState *s = ASC(obj); diff --git a/hw/char/Kconfig b/hw/char/Kconfig index 6b6cf2f..4fd74ea 100644 --- a/hw/char/Kconfig +++ b/hw/char/Kconfig @@ -41,6 +41,9 @@ config VIRTIO_SERIAL config STM32F2XX_USART bool +config STM32L4X5_USART + bool + config CMSDK_APB_UART bool diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c index db31d7c..77d9a2a 100644 --- a/hw/char/cadence_uart.c +++ b/hw/char/cadence_uart.c @@ -525,7 +525,7 @@ static void cadence_uart_reset_init(Object *obj, ResetType type) s->r[R_TTRIG] = 0x00000020; } -static void cadence_uart_reset_hold(Object *obj) +static void cadence_uart_reset_hold(Object *obj, ResetType type) { CadenceUARTState *s = CADENCE_UART(obj); diff --git a/hw/char/meson.build b/hw/char/meson.build index 006d20f..e5b13b6 100644 --- a/hw/char/meson.build +++ b/hw/char/meson.build @@ -31,6 +31,7 @@ system_ss.add(when: 'CONFIG_RENESAS_SCI', if_true: files('renesas_sci.c')) system_ss.add(when: 'CONFIG_SIFIVE_UART', if_true: files('sifive_uart.c')) system_ss.add(when: 'CONFIG_SH_SCI', if_true: files('sh_serial.c')) system_ss.add(when: 'CONFIG_STM32F2XX_USART', if_true: files('stm32f2xx_usart.c')) +system_ss.add(when: 'CONFIG_STM32L4X5_USART', if_true: files('stm32l4x5_usart.c')) system_ss.add(when: 'CONFIG_MCHP_PFSOC_MMUART', if_true: files('mchp_pfsoc_mmuart.c')) system_ss.add(when: 'CONFIG_HTIF', if_true: files('riscv_htif.c')) system_ss.add(when: 'CONFIG_GOLDFISH_TTY', if_true: files('goldfish_tty.c')) diff --git a/hw/char/sifive_uart.c b/hw/char/sifive_uart.c index e8716c4..7fc6787 100644 --- a/hw/char/sifive_uart.c +++ b/hw/char/sifive_uart.c @@ -214,7 +214,7 @@ static void sifive_uart_reset_enter(Object *obj, ResetType type) s->rx_fifo_len = 0; } -static void sifive_uart_reset_hold(Object *obj) +static void sifive_uart_reset_hold(Object *obj, ResetType type) { SiFiveUARTState *s = SIFIVE_UART(obj); qemu_irq_lower(s->irq); diff --git a/hw/char/stm32l4x5_usart.c b/hw/char/stm32l4x5_usart.c new file mode 100644 index 0000000..2627aab --- /dev/null +++ b/hw/char/stm32l4x5_usart.c @@ -0,0 +1,637 @@ +/* + * STM32L4X5 USART (Universal Synchronous Asynchronous Receiver Transmitter) + * + * Copyright (c) 2023 Arnaud Minier <arnaud.minier@telecom-paris.fr> + * Copyright (c) 2023 Inès Varhol <ines.varhol@telecom-paris.fr> + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + * The STM32L4X5 USART is heavily inspired by the stm32f2xx_usart + * by Alistair Francis. + * The reference used is the STMicroElectronics RM0351 Reference manual + * for STM32L4x5 and STM32L4x6 advanced Arm ® -based 32-bit MCUs. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qapi/error.h" +#include "chardev/char-fe.h" +#include "chardev/char-serial.h" +#include "migration/vmstate.h" +#include "hw/char/stm32l4x5_usart.h" +#include "hw/clock.h" +#include "hw/irq.h" +#include "hw/qdev-clock.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" +#include "hw/registerfields.h" +#include "trace.h" + + +REG32(CR1, 0x00) + FIELD(CR1, M1, 28, 1) /* Word length (part 2, see M0) */ + FIELD(CR1, EOBIE, 27, 1) /* End of Block interrupt enable */ + FIELD(CR1, RTOIE, 26, 1) /* Receiver timeout interrupt enable */ + FIELD(CR1, DEAT, 21, 5) /* Driver Enable assertion time */ + FIELD(CR1, DEDT, 16, 5) /* Driver Enable de-assertion time */ + FIELD(CR1, OVER8, 15, 1) /* Oversampling mode */ + FIELD(CR1, CMIE, 14, 1) /* Character match interrupt enable */ + FIELD(CR1, MME, 13, 1) /* Mute mode enable */ + FIELD(CR1, M0, 12, 1) /* Word length (part 1, see M1) */ + FIELD(CR1, WAKE, 11, 1) /* Receiver wakeup method */ + FIELD(CR1, PCE, 10, 1) /* Parity control enable */ + FIELD(CR1, PS, 9, 1) /* Parity selection */ + FIELD(CR1, PEIE, 8, 1) /* PE interrupt enable */ + FIELD(CR1, TXEIE, 7, 1) /* TXE interrupt enable */ + FIELD(CR1, TCIE, 6, 1) /* Transmission complete interrupt enable */ + FIELD(CR1, RXNEIE, 5, 1) /* RXNE interrupt enable */ + FIELD(CR1, IDLEIE, 4, 1) /* IDLE interrupt enable */ + FIELD(CR1, TE, 3, 1) /* Transmitter enable */ + FIELD(CR1, RE, 2, 1) /* Receiver enable */ + FIELD(CR1, UESM, 1, 1) /* USART enable in Stop mode */ + FIELD(CR1, UE, 0, 1) /* USART enable */ +REG32(CR2, 0x04) + FIELD(CR2, ADD_1, 28, 4) /* ADD[7:4] */ + FIELD(CR2, ADD_0, 24, 1) /* ADD[3:0] */ + FIELD(CR2, RTOEN, 23, 1) /* Receiver timeout enable */ + FIELD(CR2, ABRMOD, 21, 2) /* Auto baud rate mode */ + FIELD(CR2, ABREN, 20, 1) /* Auto baud rate enable */ + FIELD(CR2, MSBFIRST, 19, 1) /* Most significant bit first */ + FIELD(CR2, DATAINV, 18, 1) /* Binary data inversion */ + FIELD(CR2, TXINV, 17, 1) /* TX pin active level inversion */ + FIELD(CR2, RXINV, 16, 1) /* RX pin active level inversion */ + FIELD(CR2, SWAP, 15, 1) /* Swap RX/TX pins */ + FIELD(CR2, LINEN, 14, 1) /* LIN mode enable */ + FIELD(CR2, STOP, 12, 2) /* STOP bits */ + FIELD(CR2, CLKEN, 11, 1) /* Clock enable */ + FIELD(CR2, CPOL, 10, 1) /* Clock polarity */ + FIELD(CR2, CPHA, 9, 1) /* Clock phase */ + FIELD(CR2, LBCL, 8, 1) /* Last bit clock pulse */ + FIELD(CR2, LBDIE, 6, 1) /* LIN break detection interrupt enable */ + FIELD(CR2, LBDL, 5, 1) /* LIN break detection length */ + FIELD(CR2, ADDM7, 4, 1) /* 7-bit / 4-bit Address Detection */ + +REG32(CR3, 0x08) + /* TCBGTIE only on STM32L496xx/4A6xx devices */ + FIELD(CR3, UCESM, 23, 1) /* USART Clock Enable in Stop Mode */ + FIELD(CR3, WUFIE, 22, 1) /* Wakeup from Stop mode interrupt enable */ + FIELD(CR3, WUS, 20, 2) /* Wakeup from Stop mode interrupt flag selection */ + FIELD(CR3, SCARCNT, 17, 3) /* Smartcard auto-retry count */ + FIELD(CR3, DEP, 15, 1) /* Driver enable polarity selection */ + FIELD(CR3, DEM, 14, 1) /* Driver enable mode */ + FIELD(CR3, DDRE, 13, 1) /* DMA Disable on Reception Error */ + FIELD(CR3, OVRDIS, 12, 1) /* Overrun Disable */ + FIELD(CR3, ONEBIT, 11, 1) /* One sample bit method enable */ + FIELD(CR3, CTSIE, 10, 1) /* CTS interrupt enable */ + FIELD(CR3, CTSE, 9, 1) /* CTS enable */ + FIELD(CR3, RTSE, 8, 1) /* RTS enable */ + FIELD(CR3, DMAT, 7, 1) /* DMA enable transmitter */ + FIELD(CR3, DMAR, 6, 1) /* DMA enable receiver */ + FIELD(CR3, SCEN, 5, 1) /* Smartcard mode enable */ + FIELD(CR3, NACK, 4, 1) /* Smartcard NACK enable */ + FIELD(CR3, HDSEL, 3, 1) /* Half-duplex selection */ + FIELD(CR3, IRLP, 2, 1) /* IrDA low-power */ + FIELD(CR3, IREN, 1, 1) /* IrDA mode enable */ + FIELD(CR3, EIE, 0, 1) /* Error interrupt enable */ +REG32(BRR, 0x0C) + FIELD(BRR, BRR, 0, 16) +REG32(GTPR, 0x10) + FIELD(GTPR, GT, 8, 8) /* Guard time value */ + FIELD(GTPR, PSC, 0, 8) /* Prescaler value */ +REG32(RTOR, 0x14) + FIELD(RTOR, BLEN, 24, 8) /* Block Length */ + FIELD(RTOR, RTO, 0, 24) /* Receiver timeout value */ +REG32(RQR, 0x18) + FIELD(RQR, TXFRQ, 4, 1) /* Transmit data flush request */ + FIELD(RQR, RXFRQ, 3, 1) /* Receive data flush request */ + FIELD(RQR, MMRQ, 2, 1) /* Mute mode request */ + FIELD(RQR, SBKRQ, 1, 1) /* Send break request */ + FIELD(RQR, ABBRRQ, 0, 1) /* Auto baud rate request */ +REG32(ISR, 0x1C) + /* TCBGT only for STM32L475xx/476xx/486xx devices */ + FIELD(ISR, REACK, 22, 1) /* Receive enable acknowledge flag */ + FIELD(ISR, TEACK, 21, 1) /* Transmit enable acknowledge flag */ + FIELD(ISR, WUF, 20, 1) /* Wakeup from Stop mode flag */ + FIELD(ISR, RWU, 19, 1) /* Receiver wakeup from Mute mode */ + FIELD(ISR, SBKF, 18, 1) /* Send break flag */ + FIELD(ISR, CMF, 17, 1) /* Character match flag */ + FIELD(ISR, BUSY, 16, 1) /* Busy flag */ + FIELD(ISR, ABRF, 15, 1) /* Auto Baud rate flag */ + FIELD(ISR, ABRE, 14, 1) /* Auto Baud rate error */ + FIELD(ISR, EOBF, 12, 1) /* End of block flag */ + FIELD(ISR, RTOF, 11, 1) /* Receiver timeout */ + FIELD(ISR, CTS, 10, 1) /* CTS flag */ + FIELD(ISR, CTSIF, 9, 1) /* CTS interrupt flag */ + FIELD(ISR, LBDF, 8, 1) /* LIN break detection flag */ + FIELD(ISR, TXE, 7, 1) /* Transmit data register empty */ + FIELD(ISR, TC, 6, 1) /* Transmission complete */ + FIELD(ISR, RXNE, 5, 1) /* Read data register not empty */ + FIELD(ISR, IDLE, 4, 1) /* Idle line detected */ + FIELD(ISR, ORE, 3, 1) /* Overrun error */ + FIELD(ISR, NF, 2, 1) /* START bit Noise detection flag */ + FIELD(ISR, FE, 1, 1) /* Framing Error */ + FIELD(ISR, PE, 0, 1) /* Parity Error */ +REG32(ICR, 0x20) + FIELD(ICR, WUCF, 20, 1) /* Wakeup from Stop mode clear flag */ + FIELD(ICR, CMCF, 17, 1) /* Character match clear flag */ + FIELD(ICR, EOBCF, 12, 1) /* End of block clear flag */ + FIELD(ICR, RTOCF, 11, 1) /* Receiver timeout clear flag */ + FIELD(ICR, CTSCF, 9, 1) /* CTS clear flag */ + FIELD(ICR, LBDCF, 8, 1) /* LIN break detection clear flag */ + /* TCBGTCF only on STM32L496xx/4A6xx devices */ + FIELD(ICR, TCCF, 6, 1) /* Transmission complete clear flag */ + FIELD(ICR, IDLECF, 4, 1) /* Idle line detected clear flag */ + FIELD(ICR, ORECF, 3, 1) /* Overrun error clear flag */ + FIELD(ICR, NCF, 2, 1) /* Noise detected clear flag */ + FIELD(ICR, FECF, 1, 1) /* Framing error clear flag */ + FIELD(ICR, PECF, 0, 1) /* Parity error clear flag */ +REG32(RDR, 0x24) + FIELD(RDR, RDR, 0, 9) +REG32(TDR, 0x28) + FIELD(TDR, TDR, 0, 9) + +static void stm32l4x5_update_irq(Stm32l4x5UsartBaseState *s) +{ + if (((s->isr & R_ISR_WUF_MASK) && (s->cr3 & R_CR3_WUFIE_MASK)) || + ((s->isr & R_ISR_CMF_MASK) && (s->cr1 & R_CR1_CMIE_MASK)) || + ((s->isr & R_ISR_ABRF_MASK) && (s->cr1 & R_CR1_RXNEIE_MASK)) || + ((s->isr & R_ISR_EOBF_MASK) && (s->cr1 & R_CR1_EOBIE_MASK)) || + ((s->isr & R_ISR_RTOF_MASK) && (s->cr1 & R_CR1_RTOIE_MASK)) || + ((s->isr & R_ISR_CTSIF_MASK) && (s->cr3 & R_CR3_CTSIE_MASK)) || + ((s->isr & R_ISR_LBDF_MASK) && (s->cr2 & R_CR2_LBDIE_MASK)) || + ((s->isr & R_ISR_TXE_MASK) && (s->cr1 & R_CR1_TXEIE_MASK)) || + ((s->isr & R_ISR_TC_MASK) && (s->cr1 & R_CR1_TCIE_MASK)) || + ((s->isr & R_ISR_RXNE_MASK) && (s->cr1 & R_CR1_RXNEIE_MASK)) || + ((s->isr & R_ISR_IDLE_MASK) && (s->cr1 & R_CR1_IDLEIE_MASK)) || + ((s->isr & R_ISR_ORE_MASK) && + ((s->cr1 & R_CR1_RXNEIE_MASK) || (s->cr3 & R_CR3_EIE_MASK))) || + /* TODO: Handle NF ? */ + ((s->isr & R_ISR_FE_MASK) && (s->cr3 & R_CR3_EIE_MASK)) || + ((s->isr & R_ISR_PE_MASK) && (s->cr1 & R_CR1_PEIE_MASK))) { + qemu_irq_raise(s->irq); + trace_stm32l4x5_usart_irq_raised(s->isr); + } else { + qemu_irq_lower(s->irq); + trace_stm32l4x5_usart_irq_lowered(); + } +} + +static int stm32l4x5_usart_base_can_receive(void *opaque) +{ + Stm32l4x5UsartBaseState *s = opaque; + + if (!(s->isr & R_ISR_RXNE_MASK)) { + return 1; + } + + return 0; +} + +static void stm32l4x5_usart_base_receive(void *opaque, const uint8_t *buf, + int size) +{ + Stm32l4x5UsartBaseState *s = opaque; + + if (!((s->cr1 & R_CR1_UE_MASK) && (s->cr1 & R_CR1_RE_MASK))) { + trace_stm32l4x5_usart_receiver_not_enabled( + FIELD_EX32(s->cr1, CR1, UE), FIELD_EX32(s->cr1, CR1, RE)); + return; + } + + /* Check if overrun detection is enabled and if there is an overrun */ + if (!(s->cr3 & R_CR3_OVRDIS_MASK) && (s->isr & R_ISR_RXNE_MASK)) { + /* + * A character has been received while + * the previous has not been read = Overrun. + */ + s->isr |= R_ISR_ORE_MASK; + trace_stm32l4x5_usart_overrun_detected(s->rdr, *buf); + } else { + /* No overrun */ + s->rdr = *buf; + s->isr |= R_ISR_RXNE_MASK; + trace_stm32l4x5_usart_rx(s->rdr); + } + + stm32l4x5_update_irq(s); +} + +/* + * Try to send tx data, and arrange to be called back later if + * we can't (ie the char backend is busy/blocking). + */ +static gboolean usart_transmit(void *do_not_use, GIOCondition cond, + void *opaque) +{ + Stm32l4x5UsartBaseState *s = STM32L4X5_USART_BASE(opaque); + int ret; + /* TODO: Handle 9 bits transmission */ + uint8_t ch = s->tdr; + + s->watch_tag = 0; + + if (!(s->cr1 & R_CR1_TE_MASK) || (s->isr & R_ISR_TXE_MASK)) { + return G_SOURCE_REMOVE; + } + + ret = qemu_chr_fe_write(&s->chr, &ch, 1); + if (ret <= 0) { + s->watch_tag = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP, + usart_transmit, s); + if (!s->watch_tag) { + /* + * Most common reason to be here is "no chardev backend": + * just insta-drain the buffer, so the serial output + * goes into a void, rather than blocking the guest. + */ + goto buffer_drained; + } + /* Transmit pending */ + trace_stm32l4x5_usart_tx_pending(); + return G_SOURCE_REMOVE; + } + +buffer_drained: + /* Character successfully sent */ + trace_stm32l4x5_usart_tx(ch); + s->isr |= R_ISR_TC_MASK | R_ISR_TXE_MASK; + stm32l4x5_update_irq(s); + return G_SOURCE_REMOVE; +} + +static void usart_cancel_transmit(Stm32l4x5UsartBaseState *s) +{ + if (s->watch_tag) { + g_source_remove(s->watch_tag); + s->watch_tag = 0; + } +} + +static void stm32l4x5_update_params(Stm32l4x5UsartBaseState *s) +{ + int speed, parity, data_bits, stop_bits; + uint32_t value, usart_div; + QEMUSerialSetParams ssp; + + /* Select the parity type */ + if (s->cr1 & R_CR1_PCE_MASK) { + if (s->cr1 & R_CR1_PS_MASK) { + parity = 'O'; + } else { + parity = 'E'; + } + } else { + parity = 'N'; + } + + /* Select the number of stop bits */ + switch (FIELD_EX32(s->cr2, CR2, STOP)) { + case 0: + stop_bits = 1; + break; + case 2: + stop_bits = 2; + break; + default: + qemu_log_mask(LOG_UNIMP, + "UNIMPLEMENTED: fractionnal stop bits; CR2[13:12] = %u", + FIELD_EX32(s->cr2, CR2, STOP)); + return; + } + + /* Select the length of the word */ + switch ((FIELD_EX32(s->cr1, CR1, M1) << 1) | FIELD_EX32(s->cr1, CR1, M0)) { + case 0: + data_bits = 8; + break; + case 1: + data_bits = 9; + break; + case 2: + data_bits = 7; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "UNDEFINED: invalid word length, CR1.M = 0b11"); + return; + } + + /* Select the baud rate */ + value = FIELD_EX32(s->brr, BRR, BRR); + if (value < 16) { + qemu_log_mask(LOG_GUEST_ERROR, + "UNDEFINED: BRR less than 16: %u", value); + return; + } + + if (FIELD_EX32(s->cr1, CR1, OVER8) == 0) { + /* + * Oversampling by 16 + * BRR = USARTDIV + */ + usart_div = value; + } else { + /* + * Oversampling by 8 + * - BRR[2:0] = USARTDIV[3:0] shifted 1 bit to the right. + * - BRR[3] must be kept cleared. + * - BRR[15:4] = USARTDIV[15:4] + * - The frequency is multiplied by 2 + */ + usart_div = ((value & 0xFFF0) | ((value & 0x0007) << 1)) / 2; + } + + speed = clock_get_hz(s->clk) / usart_div; + + ssp.speed = speed; + ssp.parity = parity; + ssp.data_bits = data_bits; + ssp.stop_bits = stop_bits; + + qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); + + trace_stm32l4x5_usart_update_params(speed, parity, data_bits, stop_bits); +} + +static void stm32l4x5_usart_base_reset_hold(Object *obj, ResetType type) +{ + Stm32l4x5UsartBaseState *s = STM32L4X5_USART_BASE(obj); + + s->cr1 = 0x00000000; + s->cr2 = 0x00000000; + s->cr3 = 0x00000000; + s->brr = 0x00000000; + s->gtpr = 0x00000000; + s->rtor = 0x00000000; + s->isr = 0x020000C0; + s->rdr = 0x00000000; + s->tdr = 0x00000000; + + usart_cancel_transmit(s); + stm32l4x5_update_irq(s); +} + +static void usart_update_rqr(Stm32l4x5UsartBaseState *s, uint32_t value) +{ + /* TXFRQ */ + /* Reset RXNE flag */ + if (value & R_RQR_RXFRQ_MASK) { + s->isr &= ~R_ISR_RXNE_MASK; + } + /* MMRQ */ + /* SBKRQ */ + /* ABRRQ */ + stm32l4x5_update_irq(s); +} + +static uint64_t stm32l4x5_usart_base_read(void *opaque, hwaddr addr, + unsigned int size) +{ + Stm32l4x5UsartBaseState *s = opaque; + uint64_t retvalue = 0; + + switch (addr) { + case A_CR1: + retvalue = s->cr1; + break; + case A_CR2: + retvalue = s->cr2; + break; + case A_CR3: + retvalue = s->cr3; + break; + case A_BRR: + retvalue = FIELD_EX32(s->brr, BRR, BRR); + break; + case A_GTPR: + retvalue = s->gtpr; + break; + case A_RTOR: + retvalue = s->rtor; + break; + case A_RQR: + /* RQR is a write only register */ + retvalue = 0x00000000; + break; + case A_ISR: + retvalue = s->isr; + break; + case A_ICR: + /* ICR is a clear register */ + retvalue = 0x00000000; + break; + case A_RDR: + retvalue = FIELD_EX32(s->rdr, RDR, RDR); + /* Reset RXNE flag */ + s->isr &= ~R_ISR_RXNE_MASK; + stm32l4x5_update_irq(s); + break; + case A_TDR: + retvalue = FIELD_EX32(s->tdr, TDR, TDR); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); + break; + } + + trace_stm32l4x5_usart_read(addr, retvalue); + + return retvalue; +} + +static void stm32l4x5_usart_base_write(void *opaque, hwaddr addr, + uint64_t val64, unsigned int size) +{ + Stm32l4x5UsartBaseState *s = opaque; + const uint32_t value = val64; + + trace_stm32l4x5_usart_write(addr, value); + + switch (addr) { + case A_CR1: + s->cr1 = value; + stm32l4x5_update_params(s); + stm32l4x5_update_irq(s); + return; + case A_CR2: + s->cr2 = value; + stm32l4x5_update_params(s); + return; + case A_CR3: + s->cr3 = value; + return; + case A_BRR: + s->brr = value; + stm32l4x5_update_params(s); + return; + case A_GTPR: + s->gtpr = value; + return; + case A_RTOR: + s->rtor = value; + return; + case A_RQR: + usart_update_rqr(s, value); + return; + case A_ISR: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: ISR is read only !\n", __func__); + return; + case A_ICR: + /* Clear the status flags */ + s->isr &= ~value; + stm32l4x5_update_irq(s); + return; + case A_RDR: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: RDR is read only !\n", __func__); + return; + case A_TDR: + s->tdr = value; + s->isr &= ~R_ISR_TXE_MASK; + usart_transmit(NULL, G_IO_OUT, s); + return; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); + } +} + +static const MemoryRegionOps stm32l4x5_usart_base_ops = { + .read = stm32l4x5_usart_base_read, + .write = stm32l4x5_usart_base_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .max_access_size = 4, + .min_access_size = 4, + .unaligned = false + }, + .impl = { + .max_access_size = 4, + .min_access_size = 4, + .unaligned = false + }, +}; + +static Property stm32l4x5_usart_base_properties[] = { + DEFINE_PROP_CHR("chardev", Stm32l4x5UsartBaseState, chr), + DEFINE_PROP_END_OF_LIST(), +}; + +static void stm32l4x5_usart_base_init(Object *obj) +{ + Stm32l4x5UsartBaseState *s = STM32L4X5_USART_BASE(obj); + + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); + + memory_region_init_io(&s->mmio, obj, &stm32l4x5_usart_base_ops, s, + TYPE_STM32L4X5_USART_BASE, 0x400); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); + + s->clk = qdev_init_clock_in(DEVICE(s), "clk", NULL, s, 0); +} + +static int stm32l4x5_usart_base_post_load(void *opaque, int version_id) +{ + Stm32l4x5UsartBaseState *s = (Stm32l4x5UsartBaseState *)opaque; + + stm32l4x5_update_params(s); + return 0; +} + +static const VMStateDescription vmstate_stm32l4x5_usart_base = { + .name = TYPE_STM32L4X5_USART_BASE, + .version_id = 1, + .minimum_version_id = 1, + .post_load = stm32l4x5_usart_base_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT32(cr1, Stm32l4x5UsartBaseState), + VMSTATE_UINT32(cr2, Stm32l4x5UsartBaseState), + VMSTATE_UINT32(cr3, Stm32l4x5UsartBaseState), + VMSTATE_UINT32(brr, Stm32l4x5UsartBaseState), + VMSTATE_UINT32(gtpr, Stm32l4x5UsartBaseState), + VMSTATE_UINT32(rtor, Stm32l4x5UsartBaseState), + VMSTATE_UINT32(isr, Stm32l4x5UsartBaseState), + VMSTATE_UINT32(rdr, Stm32l4x5UsartBaseState), + VMSTATE_UINT32(tdr, Stm32l4x5UsartBaseState), + VMSTATE_CLOCK(clk, Stm32l4x5UsartBaseState), + VMSTATE_END_OF_LIST() + } +}; + + +static void stm32l4x5_usart_base_realize(DeviceState *dev, Error **errp) +{ + ERRP_GUARD(); + Stm32l4x5UsartBaseState *s = STM32L4X5_USART_BASE(dev); + if (!clock_has_source(s->clk)) { + error_setg(errp, "USART clock must be wired up by SoC code"); + return; + } + + qemu_chr_fe_set_handlers(&s->chr, stm32l4x5_usart_base_can_receive, + stm32l4x5_usart_base_receive, NULL, NULL, + s, NULL, true); +} + +static void stm32l4x5_usart_base_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + + rc->phases.hold = stm32l4x5_usart_base_reset_hold; + device_class_set_props(dc, stm32l4x5_usart_base_properties); + dc->realize = stm32l4x5_usart_base_realize; + dc->vmsd = &vmstate_stm32l4x5_usart_base; +} + +static void stm32l4x5_usart_class_init(ObjectClass *oc, void *data) +{ + Stm32l4x5UsartBaseClass *subc = STM32L4X5_USART_BASE_CLASS(oc); + + subc->type = STM32L4x5_USART; +} + +static void stm32l4x5_uart_class_init(ObjectClass *oc, void *data) +{ + Stm32l4x5UsartBaseClass *subc = STM32L4X5_USART_BASE_CLASS(oc); + + subc->type = STM32L4x5_UART; +} + +static void stm32l4x5_lpuart_class_init(ObjectClass *oc, void *data) +{ + Stm32l4x5UsartBaseClass *subc = STM32L4X5_USART_BASE_CLASS(oc); + + subc->type = STM32L4x5_LPUART; +} + +static const TypeInfo stm32l4x5_usart_types[] = { + { + .name = TYPE_STM32L4X5_USART_BASE, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Stm32l4x5UsartBaseState), + .instance_init = stm32l4x5_usart_base_init, + .class_init = stm32l4x5_usart_base_class_init, + .abstract = true, + }, { + .name = TYPE_STM32L4X5_USART, + .parent = TYPE_STM32L4X5_USART_BASE, + .class_init = stm32l4x5_usart_class_init, + }, { + .name = TYPE_STM32L4X5_UART, + .parent = TYPE_STM32L4X5_USART_BASE, + .class_init = stm32l4x5_uart_class_init, + }, { + .name = TYPE_STM32L4X5_LPUART, + .parent = TYPE_STM32L4X5_USART_BASE, + .class_init = stm32l4x5_lpuart_class_init, + } +}; + +DEFINE_TYPES(stm32l4x5_usart_types) diff --git a/hw/char/trace-events b/hw/char/trace-events index 7a398c8..8875758 100644 --- a/hw/char/trace-events +++ b/hw/char/trace-events @@ -106,6 +106,18 @@ cadence_uart_baudrate(unsigned baudrate) "baudrate %u" sh_serial_read(char *id, unsigned size, uint64_t offs, uint64_t val) " %s size %d offs 0x%02" PRIx64 " -> 0x%02" PRIx64 sh_serial_write(char *id, unsigned size, uint64_t offs, uint64_t val) "%s size %d offs 0x%02" PRIx64 " <- 0x%02" PRIx64 +# stm32l4x5_usart.c +stm32l4x5_usart_read(uint64_t addr, uint32_t data) "USART: Read <0x%" PRIx64 "> -> 0x%" PRIx32 "" +stm32l4x5_usart_write(uint64_t addr, uint32_t data) "USART: Write <0x%" PRIx64 "> <- 0x%" PRIx32 "" +stm32l4x5_usart_rx(uint8_t c) "USART: got character 0x%x from backend" +stm32l4x5_usart_tx(uint8_t c) "USART: character 0x%x sent to backend" +stm32l4x5_usart_tx_pending(void) "USART: character send to backend pending" +stm32l4x5_usart_irq_raised(uint32_t reg) "USART: IRQ raised: 0x%08"PRIx32 +stm32l4x5_usart_irq_lowered(void) "USART: IRQ lowered" +stm32l4x5_usart_overrun_detected(uint8_t current, uint8_t received) "USART: Overrun detected, RDR='0x%x', received 0x%x" +stm32l4x5_usart_receiver_not_enabled(uint8_t ue_bit, uint8_t re_bit) "USART: Receiver not enabled, UE=0x%x, RE=0x%x" +stm32l4x5_usart_update_params(int speed, uint8_t parity, int data, int stop) "USART: speed: %d, parity: %c, data bits: %d, stop bits: %d" + # xen_console.c xen_console_connect(unsigned int idx, unsigned int ring_ref, unsigned int port, unsigned int limit) "idx %u ring_ref %u port %u limit %u" xen_console_disconnect(unsigned int idx) "idx %u" diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c index 4bd9c70..a72d48d 100644 --- a/hw/core/cpu-common.c +++ b/hw/core/cpu-common.c @@ -113,7 +113,7 @@ void cpu_reset(CPUState *cpu) trace_cpu_reset(cpu->cpu_index); } -static void cpu_common_reset_hold(Object *obj) +static void cpu_common_reset_hold(Object *obj, ResetType type) { CPUState *cpu = CPU(obj); CPUClass *cc = CPU_GET_CLASS(cpu); diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 00efaf1..f3a996f 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -760,10 +760,10 @@ static void device_phases_reset(DeviceState *dev) rc->phases.enter(OBJECT(dev), RESET_TYPE_COLD); } if (rc->phases.hold) { - rc->phases.hold(OBJECT(dev)); + rc->phases.hold(OBJECT(dev), RESET_TYPE_COLD); } if (rc->phases.exit) { - rc->phases.exit(OBJECT(dev)); + rc->phases.exit(OBJECT(dev), RESET_TYPE_COLD); } } diff --git a/hw/core/reset.c b/hw/core/reset.c index d50da7e..58dfc8d 100644 --- a/hw/core/reset.c +++ b/hw/core/reset.c @@ -44,13 +44,6 @@ static ResettableContainer *get_root_reset_container(void) } /* - * Reason why the currently in-progress qemu_devices_reset() was called. - * If we made at least SHUTDOWN_CAUSE_SNAPSHOT_LOAD have a corresponding - * ResetType we could perhaps avoid the need for this global. - */ -static ShutdownCause device_reset_reason; - -/* * This is an Object which implements Resettable simply to call the * callback function in the hold phase. */ @@ -73,12 +66,11 @@ static ResettableState *legacy_reset_get_state(Object *obj) return &lr->reset_state; } -static void legacy_reset_hold(Object *obj) +static void legacy_reset_hold(Object *obj, ResetType type) { LegacyReset *lr = LEGACY_RESET(obj); - if (device_reset_reason == SHUTDOWN_CAUSE_SNAPSHOT_LOAD && - lr->skip_on_snapshot_load) { + if (type == RESET_TYPE_SNAPSHOT_LOAD && lr->skip_on_snapshot_load) { return; } lr->func(lr->opaque); @@ -180,8 +172,9 @@ void qemu_unregister_resettable(Object *obj) void qemu_devices_reset(ShutdownCause reason) { - device_reset_reason = reason; + ResetType type = (reason == SHUTDOWN_CAUSE_SNAPSHOT_LOAD) ? + RESET_TYPE_SNAPSHOT_LOAD : RESET_TYPE_COLD; /* Reset the simulation */ - resettable_reset(OBJECT(get_root_reset_container()), RESET_TYPE_COLD); + resettable_reset(OBJECT(get_root_reset_container()), type); } diff --git a/hw/core/resettable.c b/hw/core/resettable.c index c3df75c..6dd3e3d 100644 --- a/hw/core/resettable.c +++ b/hw/core/resettable.c @@ -48,8 +48,6 @@ void resettable_reset(Object *obj, ResetType type) void resettable_assert_reset(Object *obj, ResetType type) { - /* TODO: change this assert when adding support for other reset types */ - assert(type == RESET_TYPE_COLD); trace_resettable_reset_assert_begin(obj, type); assert(!enter_phase_in_progress); @@ -64,8 +62,6 @@ void resettable_assert_reset(Object *obj, ResetType type) void resettable_release_reset(Object *obj, ResetType type) { - /* TODO: change this assert when adding support for other reset types */ - assert(type == RESET_TYPE_COLD); trace_resettable_reset_release_begin(obj, type); assert(!enter_phase_in_progress); @@ -181,7 +177,7 @@ static void resettable_phase_hold(Object *obj, void *opaque, ResetType type) trace_resettable_transitional_function(obj, obj_typename); tr_func(obj); } else if (rc->phases.hold) { - rc->phases.hold(obj); + rc->phases.hold(obj, type); } } trace_resettable_phase_hold_end(obj, obj_typename, s->count); @@ -204,7 +200,7 @@ static void resettable_phase_exit(Object *obj, void *opaque, ResetType type) if (--s->count == 0) { trace_resettable_phase_exit_exec(obj, obj_typename, !!rc->phases.exit); if (rc->phases.exit && !resettable_get_tr_func(rc, obj)) { - rc->phases.exit(obj); + rc->phases.exit(obj, type); } } s->exit_phase_in_progress = false; diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c index 94d3353..276f315 100644 --- a/hw/display/virtio-vga.c +++ b/hw/display/virtio-vga.c @@ -180,14 +180,14 @@ static void virtio_vga_base_realize(VirtIOPCIProxy *vpci_dev, Error **errp) } } -static void virtio_vga_base_reset_hold(Object *obj) +static void virtio_vga_base_reset_hold(Object *obj, ResetType type) { VirtIOVGABaseClass *klass = VIRTIO_VGA_BASE_GET_CLASS(obj); VirtIOVGABase *vvga = VIRTIO_VGA_BASE(obj); /* reset virtio-gpu */ if (klass->parent_phases.hold) { - klass->parent_phases.hold(obj); + klass->parent_phases.hold(obj, type); } /* reset vga */ diff --git a/hw/dma/soc_dma.c b/hw/dma/soc_dma.c index 3a43005..d5c52b8 100644 --- a/hw/dma/soc_dma.c +++ b/hw/dma/soc_dma.c @@ -209,9 +209,9 @@ void soc_dma_set_request(struct soc_dma_ch_s *ch, int level) dma->enabled_count += level - ch->enable; if (level) - dma->ch_enable_mask |= 1 << ch->num; + dma->ch_enable_mask |= (uint64_t)1 << ch->num; else - dma->ch_enable_mask &= ~(1 << ch->num); + dma->ch_enable_mask &= ~((uint64_t)1 << ch->num); if (level != ch->enable) { soc_dma_ch_freq_update(dma); diff --git a/hw/gpio/npcm7xx_gpio.c b/hw/gpio/npcm7xx_gpio.c index 6e70ac1..ba19b9e 100644 --- a/hw/gpio/npcm7xx_gpio.c +++ b/hw/gpio/npcm7xx_gpio.c @@ -352,7 +352,7 @@ static void npcm7xx_gpio_enter_reset(Object *obj, ResetType type) s->regs[NPCM7XX_GPIO_ODSC] = s->reset_odsc; } -static void npcm7xx_gpio_hold_reset(Object *obj) +static void npcm7xx_gpio_hold_reset(Object *obj, ResetType type) { NPCM7xxGPIOState *s = NPCM7XX_GPIO(obj); diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c index 86f2383..d5838b8 100644 --- a/hw/gpio/pl061.c +++ b/hw/gpio/pl061.c @@ -484,7 +484,7 @@ static void pl061_enter_reset(Object *obj, ResetType type) s->amsel = 0; } -static void pl061_hold_reset(Object *obj) +static void pl061_hold_reset(Object *obj, ResetType type) { PL061State *s = PL061(obj); int i, level; diff --git a/hw/gpio/stm32l4x5_gpio.c b/hw/gpio/stm32l4x5_gpio.c index 63b8763..71bf5fd 100644 --- a/hw/gpio/stm32l4x5_gpio.c +++ b/hw/gpio/stm32l4x5_gpio.c @@ -70,7 +70,7 @@ static bool is_push_pull(Stm32l4x5GpioState *s, unsigned pin) return extract32(s->otyper, pin, 1) == 0; } -static void stm32l4x5_gpio_reset_hold(Object *obj) +static void stm32l4x5_gpio_reset_hold(Object *obj, ResetType type) { Stm32l4x5GpioState *s = STM32L4X5_GPIO(obj); diff --git a/hw/hyperv/vmbus.c b/hw/hyperv/vmbus.c index f33afee..490d805 100644 --- a/hw/hyperv/vmbus.c +++ b/hw/hyperv/vmbus.c @@ -2453,7 +2453,7 @@ static void vmbus_unrealize(BusState *bus) qemu_mutex_destroy(&vmbus->rx_queue_lock); } -static void vmbus_reset_hold(Object *obj) +static void vmbus_reset_hold(Object *obj, ResetType type) { vmbus_deinit(VMBUS(obj)); } diff --git a/hw/i2c/allwinner-i2c.c b/hw/i2c/allwinner-i2c.c index 8abcc39..16f1d6d 100644 --- a/hw/i2c/allwinner-i2c.c +++ b/hw/i2c/allwinner-i2c.c @@ -170,7 +170,7 @@ static inline bool allwinner_i2c_interrupt_is_enabled(AWI2CState *s) return s->cntr & TWI_CNTR_INT_EN; } -static void allwinner_i2c_reset_hold(Object *obj) +static void allwinner_i2c_reset_hold(Object *obj, ResetType type) { AWI2CState *s = AW_I2C(obj); @@ -385,8 +385,7 @@ static void allwinner_i2c_write(void *opaque, hwaddr offset, break; case TWI_SRST_REG: if (((value & TWI_SRST_MASK) == 0) && (s->srst & TWI_SRST_MASK)) { - /* Perform reset */ - allwinner_i2c_reset_hold(OBJECT(s)); + device_cold_reset(DEVICE(s)); } s->srst = value & TWI_SRST_MASK; break; diff --git a/hw/i2c/npcm7xx_smbus.c b/hw/i2c/npcm7xx_smbus.c index 0ea3083..22d68fc 100644 --- a/hw/i2c/npcm7xx_smbus.c +++ b/hw/i2c/npcm7xx_smbus.c @@ -1022,7 +1022,7 @@ static void npcm7xx_smbus_enter_reset(Object *obj, ResetType type) s->rx_cur = 0; } -static void npcm7xx_smbus_hold_reset(Object *obj) +static void npcm7xx_smbus_hold_reset(Object *obj, ResetType type) { NPCM7xxSMBusState *s = NPCM7XX_SMBUS(obj); diff --git a/hw/input/adb.c b/hw/input/adb.c index 98f39b4..aff7130 100644 --- a/hw/input/adb.c +++ b/hw/input/adb.c @@ -231,7 +231,7 @@ static const VMStateDescription vmstate_adb_bus = { } }; -static void adb_bus_reset_hold(Object *obj) +static void adb_bus_reset_hold(Object *obj, ResetType type) { ADBBusState *adb_bus = ADB_BUS(obj); diff --git a/hw/input/ps2.c b/hw/input/ps2.c index 00b695a..d6f8344 100644 --- a/hw/input/ps2.c +++ b/hw/input/ps2.c @@ -1007,7 +1007,7 @@ void ps2_write_mouse(PS2MouseState *s, int val) } } -static void ps2_reset_hold(Object *obj) +static void ps2_reset_hold(Object *obj, ResetType type) { PS2State *s = PS2_DEVICE(obj); @@ -1015,7 +1015,7 @@ static void ps2_reset_hold(Object *obj) ps2_reset_queue(s); } -static void ps2_reset_exit(Object *obj) +static void ps2_reset_exit(Object *obj, ResetType type) { PS2State *s = PS2_DEVICE(obj); @@ -1048,7 +1048,7 @@ static void ps2_common_post_load(PS2State *s) q->cwptr = ccount ? (q->rptr + ccount) & (PS2_BUFFER_SIZE - 1) : -1; } -static void ps2_kbd_reset_hold(Object *obj) +static void ps2_kbd_reset_hold(Object *obj, ResetType type) { PS2DeviceClass *ps2dc = PS2_DEVICE_GET_CLASS(obj); PS2KbdState *s = PS2_KBD_DEVICE(obj); @@ -1056,7 +1056,7 @@ static void ps2_kbd_reset_hold(Object *obj) trace_ps2_kbd_reset(s); if (ps2dc->parent_phases.hold) { - ps2dc->parent_phases.hold(obj); + ps2dc->parent_phases.hold(obj, type); } s->scan_enabled = 1; @@ -1065,7 +1065,7 @@ static void ps2_kbd_reset_hold(Object *obj) s->modifiers = 0; } -static void ps2_mouse_reset_hold(Object *obj) +static void ps2_mouse_reset_hold(Object *obj, ResetType type) { PS2DeviceClass *ps2dc = PS2_DEVICE_GET_CLASS(obj); PS2MouseState *s = PS2_MOUSE_DEVICE(obj); @@ -1073,7 +1073,7 @@ static void ps2_mouse_reset_hold(Object *obj) trace_ps2_mouse_reset(s); if (ps2dc->parent_phases.hold) { - ps2dc->parent_phases.hold(obj); + ps2dc->parent_phases.hold(obj, type); } s->mouse_status = 0; diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c index 94c173c..53fb2c4 100644 --- a/hw/intc/arm_gic_common.c +++ b/hw/intc/arm_gic_common.c @@ -263,7 +263,7 @@ static inline void arm_gic_common_reset_irq_state(GICState *s, int cidx, } } -static void arm_gic_common_reset_hold(Object *obj) +static void arm_gic_common_reset_hold(Object *obj, ResetType type) { GICState *s = ARM_GIC_COMMON(obj); int i, j; diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index e0d9e51..53defee 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -473,13 +473,13 @@ static void kvm_arm_gic_get(GICState *s) } } -static void kvm_arm_gic_reset_hold(Object *obj) +static void kvm_arm_gic_reset_hold(Object *obj, ResetType type) { GICState *s = ARM_GIC_COMMON(obj); KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s); if (kgc->parent_phases.hold) { - kgc->parent_phases.hold(obj); + kgc->parent_phases.hold(obj, type); } if (kvm_arm_gic_can_save_restore(s)) { diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c index 0b8f79a..58e18ff 100644 --- a/hw/intc/arm_gicv3.c +++ b/hw/intc/arm_gicv3.c @@ -21,7 +21,7 @@ #include "hw/intc/arm_gicv3.h" #include "gicv3_internal.h" -static bool irqbetter(GICv3CPUState *cs, int irq, uint8_t prio) +static bool irqbetter(GICv3CPUState *cs, int irq, uint8_t prio, bool nmi) { /* Return true if this IRQ at this priority should take * precedence over the current recorded highest priority @@ -30,14 +30,23 @@ static bool irqbetter(GICv3CPUState *cs, int irq, uint8_t prio) * is the same as this one (a property which the calling code * relies on). */ - if (prio < cs->hppi.prio) { - return true; + if (prio != cs->hppi.prio) { + return prio < cs->hppi.prio; + } + + /* + * The same priority IRQ with non-maskable property should signal to + * the CPU as it have the priority higher than the labelled 0x80 or 0x00. + */ + if (nmi != cs->hppi.nmi) { + return nmi; } + /* If multiple pending interrupts have the same priority then it is an * IMPDEF choice which of them to signal to the CPU. We choose to * signal the one with the lowest interrupt number. */ - if (prio == cs->hppi.prio && irq <= cs->hppi.irq) { + if (irq <= cs->hppi.irq) { return true; } return false; @@ -129,6 +138,40 @@ static uint32_t gicr_int_pending(GICv3CPUState *cs) return pend; } +static bool gicv3_get_priority(GICv3CPUState *cs, bool is_redist, int irq, + uint8_t *prio) +{ + uint32_t nmi = 0x0; + + if (is_redist) { + nmi = extract32(cs->gicr_inmir0, irq, 1); + } else { + nmi = *gic_bmp_ptr32(cs->gic->nmi, irq); + nmi = nmi & (1 << (irq & 0x1f)); + } + + if (nmi) { + /* DS = 0 & Non-secure NMI */ + if (!(cs->gic->gicd_ctlr & GICD_CTLR_DS) && + ((is_redist && extract32(cs->gicr_igroupr0, irq, 1)) || + (!is_redist && gicv3_gicd_group_test(cs->gic, irq)))) { + *prio = 0x80; + } else { + *prio = 0x0; + } + + return true; + } + + if (is_redist) { + *prio = cs->gicr_ipriorityr[irq]; + } else { + *prio = cs->gic->gicd_ipriority[irq]; + } + + return false; +} + /* Update the interrupt status after state in a redistributor * or CPU interface has changed, but don't tell the CPU i/f. */ @@ -141,6 +184,7 @@ static void gicv3_redist_update_noirqset(GICv3CPUState *cs) uint8_t prio; int i; uint32_t pend; + bool nmi = false; /* Find out which redistributor interrupts are eligible to be * signaled to the CPU interface. @@ -152,10 +196,11 @@ static void gicv3_redist_update_noirqset(GICv3CPUState *cs) if (!(pend & (1 << i))) { continue; } - prio = cs->gicr_ipriorityr[i]; - if (irqbetter(cs, i, prio)) { + nmi = gicv3_get_priority(cs, true, i, &prio); + if (irqbetter(cs, i, prio, nmi)) { cs->hppi.irq = i; cs->hppi.prio = prio; + cs->hppi.nmi = nmi; seenbetter = true; } } @@ -168,9 +213,10 @@ static void gicv3_redist_update_noirqset(GICv3CPUState *cs) if ((cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) && cs->gic->lpi_enable && (cs->gic->gicd_ctlr & GICD_CTLR_EN_GRP1NS) && (cs->hpplpi.prio != 0xff)) { - if (irqbetter(cs, cs->hpplpi.irq, cs->hpplpi.prio)) { + if (irqbetter(cs, cs->hpplpi.irq, cs->hpplpi.prio, cs->hpplpi.nmi)) { cs->hppi.irq = cs->hpplpi.irq; cs->hppi.prio = cs->hpplpi.prio; + cs->hppi.nmi = cs->hpplpi.nmi; cs->hppi.grp = cs->hpplpi.grp; seenbetter = true; } @@ -213,6 +259,7 @@ static void gicv3_update_noirqset(GICv3State *s, int start, int len) int i; uint8_t prio; uint32_t pend = 0; + bool nmi = false; assert(start >= GIC_INTERNAL); assert(len > 0); @@ -240,10 +287,11 @@ static void gicv3_update_noirqset(GICv3State *s, int start, int len) */ continue; } - prio = s->gicd_ipriority[i]; - if (irqbetter(cs, i, prio)) { + nmi = gicv3_get_priority(cs, false, i, &prio); + if (irqbetter(cs, i, prio, nmi)) { cs->hppi.irq = i; cs->hppi.prio = prio; + cs->hppi.nmi = nmi; cs->seenbetter = true; } } @@ -293,6 +341,7 @@ void gicv3_full_update_noirqset(GICv3State *s) for (i = 0; i < s->num_cpu; i++) { s->cpu[i].hppi.prio = 0xff; + s->cpu[i].hppi.nmi = false; } /* Note that we can guarantee that these functions will not diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c index cb55c72..bd50a1b 100644 --- a/hw/intc/arm_gicv3_common.c +++ b/hw/intc/arm_gicv3_common.c @@ -164,6 +164,24 @@ const VMStateDescription vmstate_gicv3_gicv4 = { } }; +static bool gicv3_cpu_nmi_needed(void *opaque) +{ + GICv3CPUState *cs = opaque; + + return cs->gic->nmi_support; +} + +static const VMStateDescription vmstate_gicv3_cpu_nmi = { + .name = "arm_gicv3_cpu/nmi", + .version_id = 1, + .minimum_version_id = 1, + .needed = gicv3_cpu_nmi_needed, + .fields = (const VMStateField[]) { + VMSTATE_UINT32(gicr_inmir0, GICv3CPUState), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_gicv3_cpu = { .name = "arm_gicv3_cpu", .version_id = 1, @@ -196,6 +214,7 @@ static const VMStateDescription vmstate_gicv3_cpu = { &vmstate_gicv3_cpu_virt, &vmstate_gicv3_cpu_sre_el1, &vmstate_gicv3_gicv4, + &vmstate_gicv3_cpu_nmi, NULL } }; @@ -238,6 +257,24 @@ const VMStateDescription vmstate_gicv3_gicd_no_migration_shift_bug = { } }; +static bool gicv3_nmi_needed(void *opaque) +{ + GICv3State *cs = opaque; + + return cs->nmi_support; +} + +const VMStateDescription vmstate_gicv3_gicd_nmi = { + .name = "arm_gicv3/gicd_nmi", + .version_id = 1, + .minimum_version_id = 1, + .needed = gicv3_nmi_needed, + .fields = (const VMStateField[]) { + VMSTATE_UINT32_ARRAY(nmi, GICv3State, GICV3_BMP_SIZE), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_gicv3 = { .name = "arm_gicv3", .version_id = 1, @@ -266,6 +303,7 @@ static const VMStateDescription vmstate_gicv3 = { }, .subsections = (const VMStateDescription * const []) { &vmstate_gicv3_gicd_no_migration_shift_bug, + &vmstate_gicv3_gicd_nmi, NULL } }; @@ -299,6 +337,12 @@ void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler, for (i = 0; i < s->num_cpu; i++) { sysbus_init_irq(sbd, &s->cpu[i].parent_vfiq); } + for (i = 0; i < s->num_cpu; i++) { + sysbus_init_irq(sbd, &s->cpu[i].parent_nmi); + } + for (i = 0; i < s->num_cpu; i++) { + sysbus_init_irq(sbd, &s->cpu[i].parent_vnmi); + } memory_region_init_io(&s->iomem_dist, OBJECT(s), ops, s, "gicv3_dist", 0x10000); @@ -451,7 +495,7 @@ static void arm_gicv3_finalize(Object *obj) g_free(s->redist_region_count); } -static void arm_gicv3_common_reset_hold(Object *obj) +static void arm_gicv3_common_reset_hold(Object *obj, ResetType type) { GICv3State *s = ARM_GICV3_COMMON(obj); int i; @@ -492,8 +536,11 @@ static void arm_gicv3_common_reset_hold(Object *obj) memset(cs->gicr_ipriorityr, 0, sizeof(cs->gicr_ipriorityr)); cs->hppi.prio = 0xff; + cs->hppi.nmi = false; cs->hpplpi.prio = 0xff; + cs->hpplpi.nmi = false; cs->hppvlpi.prio = 0xff; + cs->hppvlpi.nmi = false; /* State in the CPU interface must *not* be reset here, because it * is part of the CPU's reset domain, not the GIC device's. @@ -563,6 +610,7 @@ static Property arm_gicv3_common_properties[] = { DEFINE_PROP_UINT32("num-irq", GICv3State, num_irq, 32), DEFINE_PROP_UINT32("revision", GICv3State, revision, 3), DEFINE_PROP_BOOL("has-lpi", GICv3State, lpi_enable, 0), + DEFINE_PROP_BOOL("has-nmi", GICv3State, nmi_support, 0), DEFINE_PROP_BOOL("has-security-extensions", GICv3State, security_extn, 0), /* * Compatibility property: force 8 bits of physical priority, even diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index 67d8fd0..bdb13b0 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -21,6 +21,7 @@ #include "hw/irq.h" #include "cpu.h" #include "target/arm/cpregs.h" +#include "target/arm/cpu-features.h" #include "sysemu/tcg.h" #include "sysemu/qtest.h" @@ -157,6 +158,10 @@ static int ich_highest_active_virt_prio(GICv3CPUState *cs) int i; int aprmax = ich_num_aprs(cs); + if (cs->ich_apr[GICV3_G1NS][0] & ICV_AP1R_EL1_NMI) { + return 0x0; + } + for (i = 0; i < aprmax; i++) { uint32_t apr = cs->ich_apr[GICV3_G0][i] | cs->ich_apr[GICV3_G1NS][i]; @@ -191,6 +196,7 @@ static int hppvi_index(GICv3CPUState *cs) * correct behaviour. */ int prio = 0xff; + bool nmi = false; if (!(cs->ich_vmcr_el2 & (ICH_VMCR_EL2_VENG0 | ICH_VMCR_EL2_VENG1))) { /* Both groups disabled, definitely nothing to do */ @@ -199,6 +205,7 @@ static int hppvi_index(GICv3CPUState *cs) for (i = 0; i < cs->num_list_regs; i++) { uint64_t lr = cs->ich_lr_el2[i]; + bool thisnmi; int thisprio; if (ich_lr_state(lr) != ICH_LR_EL2_STATE_PENDING) { @@ -217,10 +224,12 @@ static int hppvi_index(GICv3CPUState *cs) } } + thisnmi = lr & ICH_LR_EL2_NMI; thisprio = ich_lr_prio(lr); - if (thisprio < prio) { + if ((thisprio < prio) || ((thisprio == prio) && (thisnmi & (!nmi)))) { prio = thisprio; + nmi = thisnmi; idx = i; } } @@ -289,6 +298,7 @@ static bool icv_hppi_can_preempt(GICv3CPUState *cs, uint64_t lr) * equivalent of these checks. */ int grp; + bool is_nmi; uint32_t mask, prio, rprio, vpmr; if (!(cs->ich_hcr_el2 & ICH_HCR_EL2_EN)) { @@ -301,10 +311,11 @@ static bool icv_hppi_can_preempt(GICv3CPUState *cs, uint64_t lr) */ prio = ich_lr_prio(lr); + is_nmi = lr & ICH_LR_EL2_NMI; vpmr = extract64(cs->ich_vmcr_el2, ICH_VMCR_EL2_VPMR_SHIFT, ICH_VMCR_EL2_VPMR_LENGTH); - if (prio >= vpmr) { + if (!is_nmi && prio >= vpmr) { /* Priority mask masks this interrupt */ return false; } @@ -326,6 +337,11 @@ static bool icv_hppi_can_preempt(GICv3CPUState *cs, uint64_t lr) return true; } + if ((prio & mask) == (rprio & mask) && is_nmi && + !(cs->ich_apr[GICV3_G1NS][0] & ICV_AP1R_EL1_NMI)) { + return true; + } + return false; } @@ -465,6 +481,7 @@ void gicv3_cpuif_virt_irq_fiq_update(GICv3CPUState *cs) int idx; int irqlevel = 0; int fiqlevel = 0; + int nmilevel = 0; idx = hppvi_index(cs); trace_gicv3_cpuif_virt_update(gicv3_redist_affid(cs), idx, @@ -482,9 +499,17 @@ void gicv3_cpuif_virt_irq_fiq_update(GICv3CPUState *cs) uint64_t lr = cs->ich_lr_el2[idx]; if (icv_hppi_can_preempt(cs, lr)) { - /* Virtual interrupts are simple: G0 are always FIQ, and G1 IRQ */ + /* + * Virtual interrupts are simple: G0 are always FIQ, and G1 are + * IRQ or NMI which depends on the ICH_LR<n>_EL2.NMI to have + * non-maskable property. + */ if (lr & ICH_LR_EL2_GROUP) { - irqlevel = 1; + if (lr & ICH_LR_EL2_NMI) { + nmilevel = 1; + } else { + irqlevel = 1; + } } else { fiqlevel = 1; } @@ -494,6 +519,7 @@ void gicv3_cpuif_virt_irq_fiq_update(GICv3CPUState *cs) trace_gicv3_cpuif_virt_set_irqs(gicv3_redist_affid(cs), fiqlevel, irqlevel); qemu_set_irq(cs->parent_vfiq, fiqlevel); qemu_set_irq(cs->parent_virq, irqlevel); + qemu_set_irq(cs->parent_vnmi, nmilevel); } static void gicv3_cpuif_virt_update(GICv3CPUState *cs) @@ -550,7 +576,11 @@ static void icv_ap_write(CPUARMState *env, const ARMCPRegInfo *ri, trace_gicv3_icv_ap_write(ri->crm & 1, regno, gicv3_redist_affid(cs), value); - cs->ich_apr[grp][regno] = value & 0xFFFFFFFFU; + if (cs->nmi_support) { + cs->ich_apr[grp][regno] = value & (0xFFFFFFFFU | ICV_AP1R_EL1_NMI); + } else { + cs->ich_apr[grp][regno] = value & 0xFFFFFFFFU; + } gicv3_cpuif_virt_irq_fiq_update(cs); return; @@ -697,7 +727,11 @@ static void icv_ctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, static uint64_t icv_rpr_read(CPUARMState *env, const ARMCPRegInfo *ri) { GICv3CPUState *cs = icc_cs_from_env(env); - int prio = ich_highest_active_virt_prio(cs); + uint64_t prio = ich_highest_active_virt_prio(cs); + + if (cs->ich_apr[GICV3_G1NS][0] & ICV_AP1R_EL1_NMI) { + prio |= ICV_RPR_EL1_NMI; + } trace_gicv3_icv_rpr_read(gicv3_redist_affid(cs), prio); return prio; @@ -736,13 +770,19 @@ static void icv_activate_irq(GICv3CPUState *cs, int idx, int grp) */ uint32_t mask = icv_gprio_mask(cs, grp); int prio = ich_lr_prio(cs->ich_lr_el2[idx]) & mask; + bool nmi = cs->ich_lr_el2[idx] & ICH_LR_EL2_NMI; int aprbit = prio >> (8 - cs->vprebits); int regno = aprbit / 32; int regbit = aprbit % 32; cs->ich_lr_el2[idx] &= ~ICH_LR_EL2_STATE_PENDING_BIT; cs->ich_lr_el2[idx] |= ICH_LR_EL2_STATE_ACTIVE_BIT; - cs->ich_apr[grp][regno] |= (1 << regbit); + + if (nmi) { + cs->ich_apr[grp][regno] |= ICV_AP1R_EL1_NMI; + } else { + cs->ich_apr[grp][regno] |= (1 << regbit); + } } static void icv_activate_vlpi(GICv3CPUState *cs) @@ -763,6 +803,7 @@ static uint64_t icv_iar_read(CPUARMState *env, const ARMCPRegInfo *ri) int grp = ri->crm == 8 ? GICV3_G0 : GICV3_G1NS; int idx = hppvi_index(cs); uint64_t intid = INTID_SPURIOUS; + int el = arm_current_el(env); if (idx == HPPVI_INDEX_VLPI) { if (cs->hppvlpi.grp == grp && icv_hppvlpi_can_preempt(cs)) { @@ -772,11 +813,16 @@ static uint64_t icv_iar_read(CPUARMState *env, const ARMCPRegInfo *ri) } else if (idx >= 0) { uint64_t lr = cs->ich_lr_el2[idx]; int thisgrp = (lr & ICH_LR_EL2_GROUP) ? GICV3_G1NS : GICV3_G0; + bool nmi = env->cp15.sctlr_el[el] & SCTLR_NMI && lr & ICH_LR_EL2_NMI; if (thisgrp == grp && icv_hppi_can_preempt(cs, lr)) { intid = ich_lr_vintid(lr); if (!gicv3_intid_is_special(intid)) { - icv_activate_irq(cs, idx, grp); + if (!nmi) { + icv_activate_irq(cs, idx, grp); + } else { + intid = INTID_NMI; + } } else { /* Interrupt goes from Pending to Invalid */ cs->ich_lr_el2[idx] &= ~ICH_LR_EL2_STATE_PENDING_BIT; @@ -795,6 +841,42 @@ static uint64_t icv_iar_read(CPUARMState *env, const ARMCPRegInfo *ri) return intid; } +static uint64_t icv_nmiar1_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + GICv3CPUState *cs = icc_cs_from_env(env); + int idx = hppvi_index(cs); + uint64_t intid = INTID_SPURIOUS; + + if (idx >= 0 && idx != HPPVI_INDEX_VLPI) { + uint64_t lr = cs->ich_lr_el2[idx]; + int thisgrp = (lr & ICH_LR_EL2_GROUP) ? GICV3_G1NS : GICV3_G0; + + if ((thisgrp == GICV3_G1NS) && icv_hppi_can_preempt(cs, lr)) { + intid = ich_lr_vintid(lr); + if (!gicv3_intid_is_special(intid)) { + if (lr & ICH_LR_EL2_NMI) { + icv_activate_irq(cs, idx, GICV3_G1NS); + } else { + intid = INTID_SPURIOUS; + } + } else { + /* Interrupt goes from Pending to Invalid */ + cs->ich_lr_el2[idx] &= ~ICH_LR_EL2_STATE_PENDING_BIT; + /* + * We will now return the (bogus) ID from the list register, + * as per the pseudocode. + */ + } + } + } + + trace_gicv3_icv_nmiar1_read(gicv3_redist_affid(cs), intid); + + gicv3_cpuif_virt_update(cs); + + return intid; +} + static uint32_t icc_fullprio_mask(GICv3CPUState *cs) { /* @@ -832,6 +914,23 @@ static int icc_highest_active_prio(GICv3CPUState *cs) */ int i; + if (cs->nmi_support) { + /* + * If an NMI is active this takes precedence over anything else + * for priority purposes; the NMI bit is only in the AP1R0 bit. + * We return here the effective priority of the NMI, which is + * either 0x0 or 0x80. Callers will need to check NMI again for + * purposes of either setting the RPR register bits or for + * prioritization of NMI vs non-NMI. + */ + if (cs->icc_apr[GICV3_G1][0] & ICC_AP1R_EL1_NMI) { + return 0; + } + if (cs->icc_apr[GICV3_G1NS][0] & ICC_AP1R_EL1_NMI) { + return (cs->gic->gicd_ctlr & GICD_CTLR_DS) ? 0 : 0x80; + } + } + for (i = 0; i < icc_num_aprs(cs); i++) { uint32_t apr = cs->icc_apr[GICV3_G0][i] | cs->icc_apr[GICV3_G1][i] | cs->icc_apr[GICV3_G1NS][i]; @@ -898,12 +997,24 @@ static bool icc_hppi_can_preempt(GICv3CPUState *cs) */ int rprio; uint32_t mask; + ARMCPU *cpu = ARM_CPU(cs->cpu); + CPUARMState *env = &cpu->env; if (icc_no_enabled_hppi(cs)) { return false; } - if (cs->hppi.prio >= cs->icc_pmr_el1) { + if (cs->hppi.nmi) { + if (!(cs->gic->gicd_ctlr & GICD_CTLR_DS) && + cs->hppi.grp == GICV3_G1NS) { + if (cs->icc_pmr_el1 < 0x80) { + return false; + } + if (arm_is_secure(env) && cs->icc_pmr_el1 == 0x80) { + return false; + } + } + } else if (cs->hppi.prio >= cs->icc_pmr_el1) { /* Priority mask masks this interrupt */ return false; } @@ -923,6 +1034,12 @@ static bool icc_hppi_can_preempt(GICv3CPUState *cs) return true; } + if (cs->hppi.nmi && (cs->hppi.prio & mask) == (rprio & mask)) { + if (!(cs->icc_apr[cs->hppi.grp][0] & ICC_AP1R_EL1_NMI)) { + return true; + } + } + return false; } @@ -931,6 +1048,7 @@ void gicv3_cpuif_update(GICv3CPUState *cs) /* Tell the CPU about its highest priority pending interrupt */ int irqlevel = 0; int fiqlevel = 0; + int nmilevel = 0; ARMCPU *cpu = ARM_CPU(cs->cpu); CPUARMState *env = &cpu->env; @@ -969,6 +1087,8 @@ void gicv3_cpuif_update(GICv3CPUState *cs) if (isfiq) { fiqlevel = 1; + } else if (cs->hppi.nmi) { + nmilevel = 1; } else { irqlevel = 1; } @@ -978,6 +1098,7 @@ void gicv3_cpuif_update(GICv3CPUState *cs) qemu_set_irq(cs->parent_fiq, fiqlevel); qemu_set_irq(cs->parent_irq, irqlevel); + qemu_set_irq(cs->parent_nmi, nmilevel); } static uint64_t icc_pmr_read(CPUARMState *env, const ARMCPRegInfo *ri) @@ -1044,8 +1165,13 @@ static void icc_activate_irq(GICv3CPUState *cs, int irq) int aprbit = prio >> (8 - cs->prebits); int regno = aprbit / 32; int regbit = aprbit % 32; + bool nmi = cs->hppi.nmi; - cs->icc_apr[cs->hppi.grp][regno] |= (1 << regbit); + if (nmi) { + cs->icc_apr[cs->hppi.grp][regno] |= ICC_AP1R_EL1_NMI; + } else { + cs->icc_apr[cs->hppi.grp][regno] |= (1 << regbit); + } if (irq < GIC_INTERNAL) { cs->gicr_iactiver0 = deposit32(cs->gicr_iactiver0, irq, 1, 1); @@ -1159,6 +1285,7 @@ static uint64_t icc_iar0_read(CPUARMState *env, const ARMCPRegInfo *ri) static uint64_t icc_iar1_read(CPUARMState *env, const ARMCPRegInfo *ri) { GICv3CPUState *cs = icc_cs_from_env(env); + int el = arm_current_el(env); uint64_t intid; if (icv_access(env, HCR_IMO)) { @@ -1172,13 +1299,44 @@ static uint64_t icc_iar1_read(CPUARMState *env, const ARMCPRegInfo *ri) } if (!gicv3_intid_is_special(intid)) { - icc_activate_irq(cs, intid); + if (cs->hppi.nmi && env->cp15.sctlr_el[el] & SCTLR_NMI) { + intid = INTID_NMI; + } else { + icc_activate_irq(cs, intid); + } } trace_gicv3_icc_iar1_read(gicv3_redist_affid(cs), intid); return intid; } +static uint64_t icc_nmiar1_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + GICv3CPUState *cs = icc_cs_from_env(env); + uint64_t intid; + + if (icv_access(env, HCR_IMO)) { + return icv_nmiar1_read(env, ri); + } + + if (!icc_hppi_can_preempt(cs)) { + intid = INTID_SPURIOUS; + } else { + intid = icc_hppir1_value(cs, env); + } + + if (!gicv3_intid_is_special(intid)) { + if (!cs->hppi.nmi) { + intid = INTID_SPURIOUS; + } else { + icc_activate_irq(cs, intid); + } + } + + trace_gicv3_icc_nmiar1_read(gicv3_redist_affid(cs), intid); + return intid; +} + static void icc_drop_prio(GICv3CPUState *cs, int grp) { /* Drop the priority of the currently active interrupt in @@ -1205,6 +1363,12 @@ static void icc_drop_prio(GICv3CPUState *cs, int grp) if (!*papr) { continue; } + + if (i == 0 && cs->nmi_support && (*papr & ICC_AP1R_EL1_NMI)) { + *papr &= (~ICC_AP1R_EL1_NMI); + break; + } + /* Clear the lowest set bit */ *papr &= *papr - 1; break; @@ -1239,6 +1403,15 @@ static int icc_highest_active_group(GICv3CPUState *cs) */ int i; + if (cs->nmi_support) { + if (cs->icc_apr[GICV3_G1][0] & ICC_AP1R_EL1_NMI) { + return GICV3_G1; + } + if (cs->icc_apr[GICV3_G1NS][0] & ICC_AP1R_EL1_NMI) { + return GICV3_G1NS; + } + } + for (i = 0; i < ARRAY_SIZE(cs->icc_apr[0]); i++) { int g0ctz = ctz32(cs->icc_apr[GICV3_G0][i]); int g1ctz = ctz32(cs->icc_apr[GICV3_G1][i]); @@ -1329,7 +1502,7 @@ static void icv_increment_eoicount(GICv3CPUState *cs) ICH_HCR_EL2_EOICOUNT_LENGTH, eoicount + 1); } -static int icv_drop_prio(GICv3CPUState *cs) +static int icv_drop_prio(GICv3CPUState *cs, bool *nmi) { /* Drop the priority of the currently active virtual interrupt * (favouring group 0 if there is a set active bit at @@ -1351,6 +1524,12 @@ static int icv_drop_prio(GICv3CPUState *cs) continue; } + if (i == 0 && cs->nmi_support && (*papr1 & ICV_AP1R_EL1_NMI)) { + *papr1 &= (~ICV_AP1R_EL1_NMI); + *nmi = true; + return 0xff; + } + /* We can't just use the bit-twiddling hack icc_drop_prio() does * because we need to return the bit number we cleared so * it can be compared against the list register's priority field. @@ -1410,6 +1589,7 @@ static void icv_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri, int irq = value & 0xffffff; int grp = ri->crm == 8 ? GICV3_G0 : GICV3_G1NS; int idx, dropprio; + bool nmi = false; trace_gicv3_icv_eoir_write(ri->crm == 8 ? 0 : 1, gicv3_redist_affid(cs), value); @@ -1422,8 +1602,8 @@ static void icv_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri, * error checks" (because that lets us avoid scanning the AP * registers twice). */ - dropprio = icv_drop_prio(cs); - if (dropprio == 0xff) { + dropprio = icv_drop_prio(cs, &nmi); + if (dropprio == 0xff && !nmi) { /* No active interrupt. It is CONSTRAINED UNPREDICTABLE * whether the list registers are checked in this * situation; we choose not to. @@ -1445,8 +1625,9 @@ static void icv_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t lr = cs->ich_lr_el2[idx]; int thisgrp = (lr & ICH_LR_EL2_GROUP) ? GICV3_G1NS : GICV3_G0; int lr_gprio = ich_lr_prio(lr) & icv_gprio_mask(cs, grp); + bool thisnmi = lr & ICH_LR_EL2_NMI; - if (thisgrp == grp && lr_gprio == dropprio) { + if (thisgrp == grp && (lr_gprio == dropprio || (thisnmi & nmi))) { if (!icv_eoi_split(env, cs) || irq >= GICV3_LPI_INTID_START) { /* * Priority drop and deactivate not split: deactivate irq now. @@ -1693,7 +1874,11 @@ static void icc_ap_write(CPUARMState *env, const ARMCPRegInfo *ri, return; } - cs->icc_apr[grp][regno] = value & 0xFFFFFFFFU; + if (cs->nmi_support) { + cs->icc_apr[grp][regno] = value & (0xFFFFFFFFU | ICC_AP1R_EL1_NMI); + } else { + cs->icc_apr[grp][regno] = value & 0xFFFFFFFFU; + } gicv3_cpuif_update(cs); } @@ -1783,7 +1968,7 @@ static void icc_dir_write(CPUARMState *env, const ARMCPRegInfo *ri, static uint64_t icc_rpr_read(CPUARMState *env, const ARMCPRegInfo *ri) { GICv3CPUState *cs = icc_cs_from_env(env); - int prio; + uint64_t prio; if (icv_access(env, HCR_FMO | HCR_IMO)) { return icv_rpr_read(env, ri); @@ -1803,6 +1988,22 @@ static uint64_t icc_rpr_read(CPUARMState *env, const ARMCPRegInfo *ri) } } + if (cs->nmi_support) { + /* NMI info is reported in the high bits of RPR */ + if (arm_feature(env, ARM_FEATURE_EL3) && !arm_is_secure(env)) { + if (cs->icc_apr[GICV3_G1NS][0] & ICC_AP1R_EL1_NMI) { + prio |= ICC_RPR_EL1_NMI; + } + } else { + if (cs->icc_apr[GICV3_G1NS][0] & ICC_AP1R_EL1_NMI) { + prio |= ICC_RPR_EL1_NSNMI; + } + if (cs->icc_apr[GICV3_G1][0] & ICC_AP1R_EL1_NMI) { + prio |= ICC_RPR_EL1_NMI; + } + } + } + trace_gicv3_icc_rpr_read(gicv3_redist_affid(cs), prio); return prio; } @@ -2482,6 +2683,15 @@ static const ARMCPRegInfo gicv3_cpuif_icc_apxr23_reginfo[] = { }, }; +static const ARMCPRegInfo gicv3_cpuif_gicv3_nmi_reginfo[] = { + { .name = "ICC_NMIAR1_EL1", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 5, + .type = ARM_CP_IO | ARM_CP_NO_RAW, + .access = PL1_R, .accessfn = gicv3_irq_access, + .readfn = icc_nmiar1_read, + }, +}; + static uint64_t ich_ap_read(CPUARMState *env, const ARMCPRegInfo *ri) { GICv3CPUState *cs = icc_cs_from_env(env); @@ -2503,7 +2713,11 @@ static void ich_ap_write(CPUARMState *env, const ARMCPRegInfo *ri, trace_gicv3_ich_ap_write(ri->crm & 1, regno, gicv3_redist_affid(cs), value); - cs->ich_apr[grp][regno] = value & 0xFFFFFFFFU; + if (cs->nmi_support) { + cs->ich_apr[grp][regno] = value & (0xFFFFFFFFU | ICV_AP1R_EL1_NMI); + } else { + cs->ich_apr[grp][regno] = value & 0xFFFFFFFFU; + } gicv3_cpuif_virt_irq_fiq_update(cs); } @@ -2620,6 +2834,11 @@ static void ich_lr_write(CPUARMState *env, const ARMCPRegInfo *ri, 8 - cs->vpribits, 0); } + /* Enforce RES0 bit in NMI field when FEAT_GICv3_NMI is not implemented */ + if (!cs->nmi_support) { + value &= ~ICH_LR_EL2_NMI; + } + cs->ich_lr_el2[regno] = value; gicv3_cpuif_virt_update(cs); } @@ -2839,6 +3058,19 @@ void gicv3_init_cpuif(GICv3State *s) define_arm_cp_regs(cpu, gicv3_cpuif_reginfo); /* + * If the CPU implements FEAT_NMI and FEAT_GICv3 it must also + * implement FEAT_GICv3_NMI, which is the CPU interface part + * of NMI support. This is distinct from whether the GIC proper + * (redistributors and distributor) have NMI support. In QEMU + * that is a property of the GIC device in s->nmi_support; + * cs->nmi_support indicates the CPU interface's support. + */ + if (cpu_isar_feature(aa64_nmi, cpu)) { + cs->nmi_support = true; + define_arm_cp_regs(cpu, gicv3_cpuif_gicv3_nmi_reginfo); + } + + /* * The CPU implementation specifies the number of supported * bits of physical priority. For backwards compatibility * of migration, we have a compat property that forces use diff --git a/hw/intc/arm_gicv3_dist.c b/hw/intc/arm_gicv3_dist.c index 35e8506..d8207ac 100644 --- a/hw/intc/arm_gicv3_dist.c +++ b/hw/intc/arm_gicv3_dist.c @@ -89,6 +89,29 @@ static int gicd_ns_access(GICv3State *s, int irq) return extract32(s->gicd_nsacr[irq / 16], (irq % 16) * 2, 2); } +static void gicd_write_bitmap_reg(GICv3State *s, MemTxAttrs attrs, + uint32_t *bmp, maskfn *maskfn, + int offset, uint32_t val) +{ + /* + * Helper routine to implement writing to a "set" register + * (GICD_INMIR, etc). + * Semantics implemented here: + * RAZ/WI for SGIs, PPIs, unimplemented IRQs + * Bits corresponding to Group 0 or Secure Group 1 interrupts RAZ/WI. + * offset should be the offset in bytes of the register from the start + * of its group. + */ + int irq = offset * 8; + + if (irq < GIC_INTERNAL || irq >= s->num_irq) { + return; + } + val &= mask_group_and_nsacr(s, attrs, maskfn, irq); + *gic_bmp_ptr32(bmp, irq) = val; + gicv3_update(s, irq, 32); +} + static void gicd_write_set_bitmap_reg(GICv3State *s, MemTxAttrs attrs, uint32_t *bmp, maskfn *maskfn, @@ -389,6 +412,7 @@ static bool gicd_readl(GICv3State *s, hwaddr offset, * by GICD_TYPER.IDbits) * MBIS == 0 (message-based SPIs not supported) * SecurityExtn == 1 if security extns supported + * NMI = 1 if Non-maskable interrupt property is supported * CPUNumber == 0 since for us ARE is always 1 * ITLinesNumber == (((max SPI IntID + 1) / 32) - 1) */ @@ -402,6 +426,7 @@ static bool gicd_readl(GICv3State *s, hwaddr offset, bool dvis = s->revision >= 4; *data = (1 << 25) | (1 << 24) | (dvis << 18) | (sec_extn << 10) | + (s->nmi_support << GICD_TYPER_NMI_SHIFT) | (s->lpi_enable << GICD_TYPER_LPIS_SHIFT) | (0xf << 19) | itlinesnumber; return true; @@ -543,6 +568,11 @@ static bool gicd_readl(GICv3State *s, hwaddr offset, /* RAZ/WI since affinity routing is always enabled */ *data = 0; return true; + case GICD_INMIR ... GICD_INMIR + 0x7f: + *data = (!s->nmi_support) ? 0 : + gicd_read_bitmap_reg(s, attrs, s->nmi, NULL, + offset - GICD_INMIR); + return true; case GICD_IROUTER ... GICD_IROUTER + 0x1fdf: { uint64_t r; @@ -752,6 +782,12 @@ static bool gicd_writel(GICv3State *s, hwaddr offset, case GICD_SPENDSGIR ... GICD_SPENDSGIR + 0xf: /* RAZ/WI since affinity routing is always enabled */ return true; + case GICD_INMIR ... GICD_INMIR + 0x7f: + if (s->nmi_support) { + gicd_write_bitmap_reg(s, attrs, s->nmi, NULL, + offset - GICD_INMIR, value); + } + return true; case GICD_IROUTER ... GICD_IROUTER + 0x1fdf: { uint64_t r; diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c index 52e9aca..bf31158 100644 --- a/hw/intc/arm_gicv3_its.c +++ b/hw/intc/arm_gicv3_its.c @@ -1950,13 +1950,13 @@ static void gicv3_arm_its_realize(DeviceState *dev, Error **errp) } } -static void gicv3_its_reset_hold(Object *obj) +static void gicv3_its_reset_hold(Object *obj, ResetType type) { GICv3ITSState *s = ARM_GICV3_ITS_COMMON(obj); GICv3ITSClass *c = ARM_GICV3_ITS_GET_CLASS(s); if (c->parent_phases.hold) { - c->parent_phases.hold(obj); + c->parent_phases.hold(obj, type); } /* Quiescent bit reset to 1 */ diff --git a/hw/intc/arm_gicv3_its_common.c b/hw/intc/arm_gicv3_its_common.c index 331d6b9..0b97362 100644 --- a/hw/intc/arm_gicv3_its_common.c +++ b/hw/intc/arm_gicv3_its_common.c @@ -123,7 +123,7 @@ void gicv3_its_init_mmio(GICv3ITSState *s, const MemoryRegionOps *ops, msi_nonbroken = true; } -static void gicv3_its_common_reset_hold(Object *obj) +static void gicv3_its_common_reset_hold(Object *obj, ResetType type) { GICv3ITSState *s = ARM_GICV3_ITS_COMMON(obj); diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c index 3befc96..35539c0 100644 --- a/hw/intc/arm_gicv3_its_kvm.c +++ b/hw/intc/arm_gicv3_its_kvm.c @@ -197,14 +197,14 @@ static void kvm_arm_its_post_load(GICv3ITSState *s) GITS_CTLR, &s->ctlr, true, &error_abort); } -static void kvm_arm_its_reset_hold(Object *obj) +static void kvm_arm_its_reset_hold(Object *obj, ResetType type) { GICv3ITSState *s = ARM_GICV3_ITS_COMMON(obj); KVMARMITSClass *c = KVM_ARM_ITS_GET_CLASS(s); int i; if (c->parent_phases.hold) { - c->parent_phases.hold(obj); + c->parent_phases.hold(obj, type); } if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c index 77eb37e..9ea6b8e 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c @@ -703,7 +703,7 @@ static void arm_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri) c->icc_ctlr_el1[GICV3_S] = c->icc_ctlr_el1[GICV3_NS]; } -static void kvm_arm_gicv3_reset_hold(Object *obj) +static void kvm_arm_gicv3_reset_hold(Object *obj, ResetType type) { GICv3State *s = ARM_GICV3_COMMON(obj); KVMARMGICv3Class *kgc = KVM_ARM_GICV3_GET_CLASS(s); @@ -711,7 +711,7 @@ static void kvm_arm_gicv3_reset_hold(Object *obj) DPRINTF("Reset\n"); if (kgc->parent_phases.hold) { - kgc->parent_phases.hold(obj); + kgc->parent_phases.hold(obj, type); } if (s->migration_blocker) { @@ -805,6 +805,11 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) return; } + if (s->nmi_support) { + error_setg(errp, "NMI is not supported with the in-kernel GIC"); + return; + } + gicv3_init_irqs_and_mmio(s, kvm_arm_gicv3_set_irq, NULL); for (i = 0; i < s->num_cpu; i++) { diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c index 8153525..90b238f 100644 --- a/hw/intc/arm_gicv3_redist.c +++ b/hw/intc/arm_gicv3_redist.c @@ -35,6 +35,15 @@ static int gicr_ns_access(GICv3CPUState *cs, int irq) return extract32(cs->gicr_nsacr, irq * 2, 2); } +static void gicr_write_bitmap_reg(GICv3CPUState *cs, MemTxAttrs attrs, + uint32_t *reg, uint32_t val) +{ + /* Helper routine to implement writing to a "set" register */ + val &= mask_group(cs, attrs); + *reg = val; + gicv3_redist_update(cs); +} + static void gicr_write_set_bitmap_reg(GICv3CPUState *cs, MemTxAttrs attrs, uint32_t *reg, uint32_t val) { @@ -111,6 +120,7 @@ static void update_for_one_lpi(GICv3CPUState *cs, int irq, ((prio == hpp->prio) && (irq <= hpp->irq))) { hpp->irq = irq; hpp->prio = prio; + hpp->nmi = false; /* LPIs and vLPIs are always non-secure Grp1 interrupts */ hpp->grp = GICV3_G1NS; } @@ -147,6 +157,7 @@ static void update_for_all_lpis(GICv3CPUState *cs, uint64_t ptbase, int i, bit; hpp->prio = 0xff; + hpp->nmi = false; for (i = GICV3_LPI_INTID_START / 8; i < pendt_size / 8; i++) { address_space_read(as, ptbase + i, MEMTXATTRS_UNSPECIFIED, &pend, 1); @@ -232,6 +243,7 @@ static void gicv3_redist_update_vlpi_only(GICv3CPUState *cs) if (!FIELD_EX64(cs->gicr_vpendbaser, GICR_VPENDBASER, VALID)) { cs->hppvlpi.prio = 0xff; + cs->hppvlpi.nmi = false; return; } @@ -406,6 +418,10 @@ static MemTxResult gicr_readl(GICv3CPUState *cs, hwaddr offset, *data = value; return MEMTX_OK; } + case GICR_INMIR0: + *data = cs->gic->nmi_support ? + gicr_read_bitmap_reg(cs, attrs, cs->gicr_inmir0) : 0; + return MEMTX_OK; case GICR_ICFGR0: case GICR_ICFGR1: { @@ -555,6 +571,12 @@ static MemTxResult gicr_writel(GICv3CPUState *cs, hwaddr offset, gicv3_redist_update(cs); return MEMTX_OK; } + case GICR_INMIR0: + if (cs->gic->nmi_support) { + gicr_write_bitmap_reg(cs, attrs, &cs->gicr_inmir0, value); + } + return MEMTX_OK; + case GICR_ICFGR0: /* Register is all RAZ/WI or RAO/WI bits */ return MEMTX_OK; diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h index 29d5cdc..bc9f518 100644 --- a/hw/intc/gicv3_internal.h +++ b/hw/intc/gicv3_internal.h @@ -52,6 +52,8 @@ #define GICD_SGIR 0x0F00 #define GICD_CPENDSGIR 0x0F10 #define GICD_SPENDSGIR 0x0F20 +#define GICD_INMIR 0x0F80 +#define GICD_INMIRnE 0x3B00 #define GICD_IROUTER 0x6000 #define GICD_IDREGS 0xFFD0 @@ -68,6 +70,7 @@ #define GICD_CTLR_E1NWF (1U << 7) #define GICD_CTLR_RWP (1U << 31) +#define GICD_TYPER_NMI_SHIFT 9 #define GICD_TYPER_LPIS_SHIFT 17 /* 16 bits EventId */ @@ -109,6 +112,7 @@ #define GICR_ICFGR1 (GICR_SGI_OFFSET + 0x0C04) #define GICR_IGRPMODR0 (GICR_SGI_OFFSET + 0x0D00) #define GICR_NSACR (GICR_SGI_OFFSET + 0x0E00) +#define GICR_INMIR0 (GICR_SGI_OFFSET + 0x0F80) /* VLPI redistributor registers, offsets from VLPI_base */ #define GICR_VPROPBASER (GICR_VLPI_OFFSET + 0x70) @@ -190,6 +194,10 @@ FIELD(GICR_VPENDBASER, VALID, 63, 1) #define ICC_CTLR_EL3_A3V (1U << 15) #define ICC_CTLR_EL3_NDS (1U << 17) +#define ICC_AP1R_EL1_NMI (1ULL << 63) +#define ICC_RPR_EL1_NSNMI (1ULL << 62) +#define ICC_RPR_EL1_NMI (1ULL << 63) + #define ICH_VMCR_EL2_VENG0_SHIFT 0 #define ICH_VMCR_EL2_VENG0 (1U << ICH_VMCR_EL2_VENG0_SHIFT) #define ICH_VMCR_EL2_VENG1_SHIFT 1 @@ -238,6 +246,7 @@ FIELD(GICR_VPENDBASER, VALID, 63, 1) #define ICH_LR_EL2_PRIORITY_SHIFT 48 #define ICH_LR_EL2_PRIORITY_LENGTH 8 #define ICH_LR_EL2_PRIORITY_MASK (0xffULL << ICH_LR_EL2_PRIORITY_SHIFT) +#define ICH_LR_EL2_NMI (1ULL << 59) #define ICH_LR_EL2_GROUP (1ULL << 60) #define ICH_LR_EL2_HW (1ULL << 61) #define ICH_LR_EL2_STATE_SHIFT 62 @@ -269,6 +278,9 @@ FIELD(GICR_VPENDBASER, VALID, 63, 1) #define ICH_VTR_EL2_PREBITS_SHIFT 26 #define ICH_VTR_EL2_PRIBITS_SHIFT 29 +#define ICV_AP1R_EL1_NMI (1ULL << 63) +#define ICV_RPR_EL1_NMI (1ULL << 63) + /* ITS Registers */ FIELD(GITS_BASER, SIZE, 0, 8) @@ -507,6 +519,7 @@ FIELD(VTE, RDBASE, 42, RDBASE_PROCNUM_LENGTH) /* Special interrupt IDs */ #define INTID_SECURE 1020 #define INTID_NONSECURE 1021 +#define INTID_NMI 1022 #define INTID_SPURIOUS 1023 /* Functions internal to the emulated GICv3 */ diff --git a/hw/intc/trace-events b/hw/intc/trace-events index 1ef29d0..47340b5 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -116,6 +116,7 @@ gicv3_cpuif_set_irqs(uint32_t cpuid, int fiqlevel, int irqlevel) "GICv3 CPU i/f gicv3_icc_generate_sgi(uint32_t cpuid, int irq, int irm, uint32_t aff, uint32_t targetlist) "GICv3 CPU i/f 0x%x generating SGI %d IRM %d target affinity 0x%xxx targetlist 0x%x" gicv3_icc_iar0_read(uint32_t cpu, uint64_t val) "GICv3 ICC_IAR0 read cpu 0x%x value 0x%" PRIx64 gicv3_icc_iar1_read(uint32_t cpu, uint64_t val) "GICv3 ICC_IAR1 read cpu 0x%x value 0x%" PRIx64 +gicv3_icc_nmiar1_read(uint32_t cpu, uint64_t val) "GICv3 ICC_NMIAR1 read cpu 0x%x value 0x%" PRIx64 gicv3_icc_eoir_write(int grp, uint32_t cpu, uint64_t val) "GICv3 ICC_EOIR%d write cpu 0x%x value 0x%" PRIx64 gicv3_icc_hppir0_read(uint32_t cpu, uint64_t val) "GICv3 ICC_HPPIR0 read cpu 0x%x value 0x%" PRIx64 gicv3_icc_hppir1_read(uint32_t cpu, uint64_t val) "GICv3 ICC_HPPIR1 read cpu 0x%x value 0x%" PRIx64 @@ -151,6 +152,7 @@ gicv3_icv_rpr_read(uint32_t cpu, uint64_t val) "GICv3 ICV_RPR read cpu 0x%x valu gicv3_icv_hppir_read(int grp, uint32_t cpu, uint64_t val) "GICv3 ICV_HPPIR%d read cpu 0x%x value 0x%" PRIx64 gicv3_icv_dir_write(uint32_t cpu, uint64_t val) "GICv3 ICV_DIR write cpu 0x%x value 0x%" PRIx64 gicv3_icv_iar_read(int grp, uint32_t cpu, uint64_t val) "GICv3 ICV_IAR%d read cpu 0x%x value 0x%" PRIx64 +gicv3_icv_nmiar1_read(uint32_t cpu, uint64_t val) "GICv3 ICV_NMIAR1 read cpu 0x%x value 0x%" PRIx64 gicv3_icv_eoir_write(int grp, uint32_t cpu, uint64_t val) "GICv3 ICV_EOIR%d write cpu 0x%x value 0x%" PRIx64 gicv3_cpuif_virt_update(uint32_t cpuid, int idx, int hppvlpi, int grp, int prio) "GICv3 CPU i/f 0x%x virt HPPI update LR index %d HPPVLPI %d grp %d prio %d" gicv3_cpuif_virt_set_irqs(uint32_t cpuid, int fiqlevel, int irqlevel) "GICv3 CPU i/f 0x%x virt HPPI update: setting FIQ %d IRQ %d" diff --git a/hw/intc/xics.c b/hw/intc/xics.c index 700abfa..9b3b7ab 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -579,7 +579,7 @@ static void ics_reset_irq(ICSIRQState *irq) irq->saved_priority = 0xff; } -static void ics_reset_hold(Object *obj) +static void ics_reset_hold(Object *obj, ResetType type) { ICSState *ics = ICS(obj); g_autofree uint8_t *flags = g_malloc(ics->nr_irqs); diff --git a/hw/m68k/q800-glue.c b/hw/m68k/q800-glue.c index b5a7713..e2ae7c3 100644 --- a/hw/m68k/q800-glue.c +++ b/hw/m68k/q800-glue.c @@ -175,7 +175,7 @@ static void glue_nmi_release(void *opaque) GLUE_set_irq(s, GLUE_IRQ_IN_NMI, 0); } -static void glue_reset_hold(Object *obj) +static void glue_reset_hold(Object *obj, ResetType type) { GLUEState *s = GLUE(obj); diff --git a/hw/misc/djmemc.c b/hw/misc/djmemc.c index 9b69656..96d5efb 100644 --- a/hw/misc/djmemc.c +++ b/hw/misc/djmemc.c @@ -96,7 +96,7 @@ static void djmemc_init(Object *obj) sysbus_init_mmio(sbd, &s->mem_regs); } -static void djmemc_reset_hold(Object *obj) +static void djmemc_reset_hold(Object *obj, ResetType type) { DJMEMCState *s = DJMEMC(obj); diff --git a/hw/misc/iosb.c b/hw/misc/iosb.c index e20305e..31927ea 100644 --- a/hw/misc/iosb.c +++ b/hw/misc/iosb.c @@ -81,7 +81,7 @@ static const MemoryRegionOps iosb_mmio_ops = { .endianness = DEVICE_BIG_ENDIAN, }; -static void iosb_reset_hold(Object *obj) +static void iosb_reset_hold(Object *obj, ResetType type) { IOSBState *s = IOSB(obj); diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c index db6142b..652395b 100644 --- a/hw/misc/mac_via.c +++ b/hw/misc/mac_via.c @@ -1203,7 +1203,7 @@ static int via1_post_load(void *opaque, int version_id) } /* VIA 1 */ -static void mos6522_q800_via1_reset_hold(Object *obj) +static void mos6522_q800_via1_reset_hold(Object *obj, ResetType type) { MOS6522Q800VIA1State *v1s = MOS6522_Q800_VIA1(obj); MOS6522State *ms = MOS6522(v1s); @@ -1211,7 +1211,7 @@ static void mos6522_q800_via1_reset_hold(Object *obj) ADBBusState *adb_bus = &v1s->adb_bus; if (mdc->parent_phases.hold) { - mdc->parent_phases.hold(obj); + mdc->parent_phases.hold(obj, type); } ms->timers[0].frequency = VIA_TIMER_FREQ; @@ -1359,13 +1359,13 @@ static void mos6522_q800_via2_portB_write(MOS6522State *s) } } -static void mos6522_q800_via2_reset_hold(Object *obj) +static void mos6522_q800_via2_reset_hold(Object *obj, ResetType type) { MOS6522State *ms = MOS6522(obj); MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(ms); if (mdc->parent_phases.hold) { - mdc->parent_phases.hold(obj); + mdc->parent_phases.hold(obj, type); } ms->timers[0].frequency = VIA_TIMER_FREQ; diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index 41934e2..beab0ff 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -586,13 +586,13 @@ static void mos6522_cuda_portB_write(MOS6522State *s) cuda_update(cs); } -static void mos6522_cuda_reset_hold(Object *obj) +static void mos6522_cuda_reset_hold(Object *obj, ResetType type) { MOS6522State *ms = MOS6522(obj); MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(ms); if (mdc->parent_phases.hold) { - mdc->parent_phases.hold(obj); + mdc->parent_phases.hold(obj, type); } ms->timers[0].frequency = CUDA_TIMER_FREQ; diff --git a/hw/misc/macio/pmu.c b/hw/misc/macio/pmu.c index e40c51b..238da58 100644 --- a/hw/misc/macio/pmu.c +++ b/hw/misc/macio/pmu.c @@ -792,7 +792,7 @@ static void mos6522_pmu_portB_write(MOS6522State *s) pmu_update(ps); } -static void mos6522_pmu_reset_hold(Object *obj) +static void mos6522_pmu_reset_hold(Object *obj, ResetType type) { MOS6522State *ms = MOS6522(obj); MOS6522PMUState *mps = container_of(ms, MOS6522PMUState, parent_obj); @@ -800,7 +800,7 @@ static void mos6522_pmu_reset_hold(Object *obj) MOS6522DeviceClass *mdc = MOS6522_GET_CLASS(ms); if (mdc->parent_phases.hold) { - mdc->parent_phases.hold(obj); + mdc->parent_phases.hold(obj, type); } ms->timers[0].frequency = VIA_TIMER_FREQ; diff --git a/hw/misc/mos6522.c b/hw/misc/mos6522.c index e3fe87c..515f62e 100644 --- a/hw/misc/mos6522.c +++ b/hw/misc/mos6522.c @@ -642,7 +642,7 @@ const VMStateDescription vmstate_mos6522 = { } }; -static void mos6522_reset_hold(Object *obj) +static void mos6522_reset_hold(Object *obj, ResetType type) { MOS6522State *s = MOS6522(obj); diff --git a/hw/misc/npcm7xx_clk.c b/hw/misc/npcm7xx_clk.c index ac1622c..2098c85 100644 --- a/hw/misc/npcm7xx_clk.c +++ b/hw/misc/npcm7xx_clk.c @@ -873,20 +873,13 @@ static void npcm7xx_clk_enter_reset(Object *obj, ResetType type) QEMU_BUILD_BUG_ON(sizeof(s->regs) != sizeof(cold_reset_values)); - switch (type) { - case RESET_TYPE_COLD: - memcpy(s->regs, cold_reset_values, sizeof(cold_reset_values)); - s->ref_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - npcm7xx_clk_update_all_clocks(s); - return; - } - + memcpy(s->regs, cold_reset_values, sizeof(cold_reset_values)); + s->ref_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + npcm7xx_clk_update_all_clocks(s); /* * A small number of registers need to be reset on a core domain reset, * but no such reset type exists yet. */ - qemu_log_mask(LOG_UNIMP, "%s: reset type %d not implemented.", - __func__, type); } static void npcm7xx_clk_init_clock_hierarchy(NPCM7xxCLKState *s) diff --git a/hw/misc/npcm7xx_gcr.c b/hw/misc/npcm7xx_gcr.c index 9252f9d..c4c4e24 100644 --- a/hw/misc/npcm7xx_gcr.c +++ b/hw/misc/npcm7xx_gcr.c @@ -159,14 +159,10 @@ static void npcm7xx_gcr_enter_reset(Object *obj, ResetType type) QEMU_BUILD_BUG_ON(sizeof(s->regs) != sizeof(cold_reset_values)); - switch (type) { - case RESET_TYPE_COLD: - memcpy(s->regs, cold_reset_values, sizeof(s->regs)); - s->regs[NPCM7XX_GCR_PWRON] = s->reset_pwron; - s->regs[NPCM7XX_GCR_MDLR] = s->reset_mdlr; - s->regs[NPCM7XX_GCR_INTCR3] = s->reset_intcr3; - break; - } + memcpy(s->regs, cold_reset_values, sizeof(s->regs)); + s->regs[NPCM7XX_GCR_PWRON] = s->reset_pwron; + s->regs[NPCM7XX_GCR_MDLR] = s->reset_mdlr; + s->regs[NPCM7XX_GCR_INTCR3] = s->reset_intcr3; } static void npcm7xx_gcr_realize(DeviceState *dev, Error **errp) diff --git a/hw/misc/npcm7xx_mft.c b/hw/misc/npcm7xx_mft.c index 9a84858..9fcc69f 100644 --- a/hw/misc/npcm7xx_mft.c +++ b/hw/misc/npcm7xx_mft.c @@ -467,7 +467,7 @@ static void npcm7xx_mft_enter_reset(Object *obj, ResetType type) npcm7xx_mft_reset(s); } -static void npcm7xx_mft_hold_reset(Object *obj) +static void npcm7xx_mft_hold_reset(Object *obj, ResetType type) { NPCM7xxMFTState *s = NPCM7XX_MFT(obj); diff --git a/hw/misc/npcm7xx_pwm.c b/hw/misc/npcm7xx_pwm.c index fca2dd2..f7f77e3 100644 --- a/hw/misc/npcm7xx_pwm.c +++ b/hw/misc/npcm7xx_pwm.c @@ -468,7 +468,7 @@ static void npcm7xx_pwm_enter_reset(Object *obj, ResetType type) s->piir = 0x00000000; } -static void npcm7xx_pwm_hold_reset(Object *obj) +static void npcm7xx_pwm_hold_reset(Object *obj, ResetType type) { NPCM7xxPWMState *s = NPCM7XX_PWM(obj); int i; diff --git a/hw/misc/stm32l4x5_exti.c b/hw/misc/stm32l4x5_exti.c index 9fd8591..a090dbd 100644 --- a/hw/misc/stm32l4x5_exti.c +++ b/hw/misc/stm32l4x5_exti.c @@ -77,7 +77,7 @@ static unsigned configurable_mask(unsigned bank) return valid_mask(bank) & ~exti_romask[bank]; } -static void stm32l4x5_exti_reset_hold(Object *obj) +static void stm32l4x5_exti_reset_hold(Object *obj, ResetType type) { Stm32l4x5ExtiState *s = STM32L4X5_EXTI(obj); diff --git a/hw/misc/stm32l4x5_rcc.c b/hw/misc/stm32l4x5_rcc.c index ed2dbd9..417bd5e 100644 --- a/hw/misc/stm32l4x5_rcc.c +++ b/hw/misc/stm32l4x5_rcc.c @@ -113,13 +113,13 @@ static void clock_mux_reset_enter(Object *obj, ResetType type) set_clock_mux_init_info(s, s->id); } -static void clock_mux_reset_hold(Object *obj) +static void clock_mux_reset_hold(Object *obj, ResetType type) { RccClockMuxState *s = RCC_CLOCK_MUX(obj); clock_mux_update(s, true); } -static void clock_mux_reset_exit(Object *obj) +static void clock_mux_reset_exit(Object *obj, ResetType type) { RccClockMuxState *s = RCC_CLOCK_MUX(obj); clock_mux_update(s, false); @@ -263,13 +263,13 @@ static void pll_reset_enter(Object *obj, ResetType type) set_pll_init_info(s, s->id); } -static void pll_reset_hold(Object *obj) +static void pll_reset_hold(Object *obj, ResetType type) { RccPllState *s = RCC_PLL(obj); pll_update(s, true); } -static void pll_reset_exit(Object *obj) +static void pll_reset_exit(Object *obj, ResetType type) { RccPllState *s = RCC_PLL(obj); pll_update(s, false); @@ -907,7 +907,7 @@ static void rcc_update_csr(Stm32l4x5RccState *s) rcc_update_irq(s); } -static void stm32l4x5_rcc_reset_hold(Object *obj) +static void stm32l4x5_rcc_reset_hold(Object *obj, ResetType type) { Stm32l4x5RccState *s = STM32L4X5_RCC(obj); s->cr = 0x00000063; diff --git a/hw/misc/stm32l4x5_syscfg.c b/hw/misc/stm32l4x5_syscfg.c index 3dafc00..a5a1ce2 100644 --- a/hw/misc/stm32l4x5_syscfg.c +++ b/hw/misc/stm32l4x5_syscfg.c @@ -65,7 +65,7 @@ #define NUM_LINES_PER_EXTICR_REG 4 -static void stm32l4x5_syscfg_hold_reset(Object *obj) +static void stm32l4x5_syscfg_hold_reset(Object *obj, ResetType type) { Stm32l4x5SyscfgState *s = STM32L4X5_SYSCFG(obj); diff --git a/hw/misc/xlnx-versal-cframe-reg.c b/hw/misc/xlnx-versal-cframe-reg.c index a6ab287..3fc838b 100644 --- a/hw/misc/xlnx-versal-cframe-reg.c +++ b/hw/misc/xlnx-versal-cframe-reg.c @@ -542,7 +542,7 @@ static void cframe_reg_reset_enter(Object *obj, ResetType type) } } -static void cframe_reg_reset_hold(Object *obj) +static void cframe_reg_reset_hold(Object *obj, ResetType type) { XlnxVersalCFrameReg *s = XLNX_VERSAL_CFRAME_REG(obj); diff --git a/hw/misc/xlnx-versal-crl.c b/hw/misc/xlnx-versal-crl.c index 1f1762e..f143900 100644 --- a/hw/misc/xlnx-versal-crl.c +++ b/hw/misc/xlnx-versal-crl.c @@ -311,7 +311,7 @@ static void crl_reset_enter(Object *obj, ResetType type) } } -static void crl_reset_hold(Object *obj) +static void crl_reset_hold(Object *obj, ResetType type) { XlnxVersalCRL *s = XLNX_VERSAL_CRL(obj); diff --git a/hw/misc/xlnx-versal-pmc-iou-slcr.c b/hw/misc/xlnx-versal-pmc-iou-slcr.c index 60e13a7..e469c04 100644 --- a/hw/misc/xlnx-versal-pmc-iou-slcr.c +++ b/hw/misc/xlnx-versal-pmc-iou-slcr.c @@ -1350,7 +1350,7 @@ static void xlnx_versal_pmc_iou_slcr_reset_init(Object *obj, ResetType type) } } -static void xlnx_versal_pmc_iou_slcr_reset_hold(Object *obj) +static void xlnx_versal_pmc_iou_slcr_reset_hold(Object *obj, ResetType type) { XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(obj); diff --git a/hw/misc/xlnx-versal-trng.c b/hw/misc/xlnx-versal-trng.c index 6495188..51eb760 100644 --- a/hw/misc/xlnx-versal-trng.c +++ b/hw/misc/xlnx-versal-trng.c @@ -632,7 +632,7 @@ static void trng_unrealize(DeviceState *dev) s->prng = NULL; } -static void trng_reset_hold(Object *obj) +static void trng_reset_hold(Object *obj, ResetType type) { trng_reset(XLNX_VERSAL_TRNG(obj)); } diff --git a/hw/misc/xlnx-versal-xramc.c b/hw/misc/xlnx-versal-xramc.c index a5f78c1..ad839ce 100644 --- a/hw/misc/xlnx-versal-xramc.c +++ b/hw/misc/xlnx-versal-xramc.c @@ -137,7 +137,7 @@ static void xram_ctrl_reset_enter(Object *obj, ResetType type) ARRAY_FIELD_DP32(s->regs, XRAM_IMP, SIZE, s->cfg.encoded_size); } -static void xram_ctrl_reset_hold(Object *obj) +static void xram_ctrl_reset_hold(Object *obj, ResetType type) { XlnxXramCtrl *s = XLNX_XRAM_CTRL(obj); diff --git a/hw/misc/xlnx-zynqmp-apu-ctrl.c b/hw/misc/xlnx-zynqmp-apu-ctrl.c index 1d441b4..87e4a14 100644 --- a/hw/misc/xlnx-zynqmp-apu-ctrl.c +++ b/hw/misc/xlnx-zynqmp-apu-ctrl.c @@ -150,7 +150,7 @@ static void zynqmp_apu_reset_enter(Object *obj, ResetType type) s->cpu_in_wfi = 0; } -static void zynqmp_apu_reset_hold(Object *obj) +static void zynqmp_apu_reset_hold(Object *obj, ResetType type) { XlnxZynqMPAPUCtrl *s = XLNX_ZYNQMP_APU_CTRL(obj); diff --git a/hw/misc/xlnx-zynqmp-crf.c b/hw/misc/xlnx-zynqmp-crf.c index a83efb44..e5aba56 100644 --- a/hw/misc/xlnx-zynqmp-crf.c +++ b/hw/misc/xlnx-zynqmp-crf.c @@ -191,7 +191,7 @@ static void crf_reset_enter(Object *obj, ResetType type) } } -static void crf_reset_hold(Object *obj) +static void crf_reset_hold(Object *obj, ResetType type) { XlnxZynqMPCRF *s = XLNX_ZYNQMP_CRF(obj); ir_update_irq(s); diff --git a/hw/misc/zynq_slcr.c b/hw/misc/zynq_slcr.c index d2ac2e7..3412ff0 100644 --- a/hw/misc/zynq_slcr.c +++ b/hw/misc/zynq_slcr.c @@ -416,7 +416,7 @@ static void zynq_slcr_reset_init(Object *obj, ResetType type) s->regs[R_DDRIOB + 12] = 0x00000021; } -static void zynq_slcr_reset_hold(Object *obj) +static void zynq_slcr_reset_hold(Object *obj, ResetType type) { ZynqSLCRState *s = ZYNQ_SLCR(obj); @@ -425,7 +425,7 @@ static void zynq_slcr_reset_hold(Object *obj) zynq_slcr_propagate_clocks(s); } -static void zynq_slcr_reset_exit(Object *obj) +static void zynq_slcr_reset_exit(Object *obj, ResetType type) { ZynqSLCRState *s = ZYNQ_SLCR(obj); diff --git a/hw/net/can/xlnx-zynqmp-can.c b/hw/net/can/xlnx-zynqmp-can.c index ca0ce4e..58f1432 100644 --- a/hw/net/can/xlnx-zynqmp-can.c +++ b/hw/net/can/xlnx-zynqmp-can.c @@ -1006,7 +1006,7 @@ static void xlnx_zynqmp_can_reset_init(Object *obj, ResetType type) ptimer_transaction_commit(s->can_timer); } -static void xlnx_zynqmp_can_reset_hold(Object *obj) +static void xlnx_zynqmp_can_reset_hold(Object *obj, ResetType type) { XlnxZynqMPCANState *s = XLNX_ZYNQMP_CAN(obj); unsigned int i; diff --git a/hw/net/e1000.c b/hw/net/e1000.c index 43f3a4a..5012b96 100644 --- a/hw/net/e1000.c +++ b/hw/net/e1000.c @@ -373,7 +373,7 @@ static bool e1000_vet_init_need(void *opaque) return chkflag(VET); } -static void e1000_reset_hold(Object *obj) +static void e1000_reset_hold(Object *obj, ResetType type) { E1000State *d = E1000(obj); E1000BaseClass *edc = E1000_GET_CLASS(d); diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c index 7c6f602..edc101e 100644 --- a/hw/net/e1000e.c +++ b/hw/net/e1000e.c @@ -513,7 +513,7 @@ static void e1000e_pci_uninit(PCIDevice *pci_dev) msi_uninit(pci_dev); } -static void e1000e_qdev_reset_hold(Object *obj) +static void e1000e_qdev_reset_hold(Object *obj, ResetType type) { E1000EState *s = E1000E(obj); diff --git a/hw/net/igb.c b/hw/net/igb.c index 9b37523..1ef6170 100644 --- a/hw/net/igb.c +++ b/hw/net/igb.c @@ -486,7 +486,7 @@ static void igb_pci_uninit(PCIDevice *pci_dev) msi_uninit(pci_dev); } -static void igb_qdev_reset_hold(Object *obj) +static void igb_qdev_reset_hold(Object *obj, ResetType type) { IGBState *s = IGB(obj); diff --git a/hw/net/igbvf.c b/hw/net/igbvf.c index 94a4e88..21a97d4 100644 --- a/hw/net/igbvf.c +++ b/hw/net/igbvf.c @@ -282,7 +282,7 @@ static void igbvf_pci_realize(PCIDevice *dev, Error **errp) pcie_ari_init(dev, 0x150); } -static void igbvf_qdev_reset_hold(Object *obj) +static void igbvf_qdev_reset_hold(Object *obj, ResetType type) { PCIDevice *vf = PCI_DEVICE(obj); diff --git a/hw/nvram/xlnx-bbram.c b/hw/nvram/xlnx-bbram.c index 0a71a00..09575a7 100644 --- a/hw/nvram/xlnx-bbram.c +++ b/hw/nvram/xlnx-bbram.c @@ -417,7 +417,7 @@ static RegisterAccessInfo bbram_ctrl_regs_info[] = { } }; -static void bbram_ctrl_reset_hold(Object *obj) +static void bbram_ctrl_reset_hold(Object *obj, ResetType type) { XlnxBBRam *s = XLNX_BBRAM(obj); unsigned int i; diff --git a/hw/nvram/xlnx-versal-efuse-ctrl.c b/hw/nvram/xlnx-versal-efuse-ctrl.c index e4b9e11..def6fe33 100644 --- a/hw/nvram/xlnx-versal-efuse-ctrl.c +++ b/hw/nvram/xlnx-versal-efuse-ctrl.c @@ -658,7 +658,7 @@ static void efuse_ctrl_register_reset(RegisterInfo *reg) register_reset(reg); } -static void efuse_ctrl_reset_hold(Object *obj) +static void efuse_ctrl_reset_hold(Object *obj, ResetType type) { XlnxVersalEFuseCtrl *s = XLNX_VERSAL_EFUSE_CTRL(obj); unsigned int i; diff --git a/hw/nvram/xlnx-zynqmp-efuse.c b/hw/nvram/xlnx-zynqmp-efuse.c index ec98456..2d465f0 100644 --- a/hw/nvram/xlnx-zynqmp-efuse.c +++ b/hw/nvram/xlnx-zynqmp-efuse.c @@ -770,7 +770,7 @@ static void zynqmp_efuse_register_reset(RegisterInfo *reg) register_reset(reg); } -static void zynqmp_efuse_reset_hold(Object *obj) +static void zynqmp_efuse_reset_hold(Object *obj, ResetType type) { XlnxZynqMPEFuse *s = XLNX_ZYNQMP_EFUSE(obj); unsigned int i; diff --git a/hw/pci-bridge/cxl_root_port.c b/hw/pci-bridge/cxl_root_port.c index 8a30da6..2dd1023 100644 --- a/hw/pci-bridge/cxl_root_port.c +++ b/hw/pci-bridge/cxl_root_port.c @@ -186,13 +186,13 @@ static void cxl_rp_realize(DeviceState *dev, Error **errp) component_bar); } -static void cxl_rp_reset_hold(Object *obj) +static void cxl_rp_reset_hold(Object *obj, ResetType type) { PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(obj); CXLRootPort *crp = CXL_ROOT_PORT(obj); if (rpc->parent_phases.hold) { - rpc->parent_phases.hold(obj); + rpc->parent_phases.hold(obj, type); } latch_registers(crp); diff --git a/hw/pci-bridge/pcie_root_port.c b/hw/pci-bridge/pcie_root_port.c index efd96bf..09a3478 100644 --- a/hw/pci-bridge/pcie_root_port.c +++ b/hw/pci-bridge/pcie_root_port.c @@ -43,7 +43,7 @@ static void rp_write_config(PCIDevice *d, uint32_t address, pcie_aer_root_write_config(d, address, val, len, root_cmd); } -static void rp_reset_hold(Object *obj) +static void rp_reset_hold(Object *obj, ResetType type) { PCIDevice *d = PCI_DEVICE(obj); DeviceState *qdev = DEVICE(obj); diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index 1f0c435..1516d00 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -590,7 +590,7 @@ static int pci_bonito_map_irq(PCIDevice *pci_dev, int irq_num) } } -static void bonito_reset_hold(Object *obj) +static void bonito_reset_hold(Object *obj, ResetType type) { PCIBonitoState *s = PCI_BONITO(obj); uint32_t val = 0; diff --git a/hw/pci-host/pnv_phb.c b/hw/pci-host/pnv_phb.c index 157c007..d4c118d 100644 --- a/hw/pci-host/pnv_phb.c +++ b/hw/pci-host/pnv_phb.c @@ -208,7 +208,7 @@ static void pnv_phb_class_init(ObjectClass *klass, void *data) dc->user_creatable = true; } -static void pnv_phb_root_port_reset_hold(Object *obj) +static void pnv_phb_root_port_reset_hold(Object *obj, ResetType type) { PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(obj); PnvPHBRootPort *phb_rp = PNV_PHB_ROOT_PORT(obj); @@ -216,7 +216,7 @@ static void pnv_phb_root_port_reset_hold(Object *obj) uint8_t *conf = d->config; if (rpc->parent_phases.hold) { - rpc->parent_phases.hold(obj); + rpc->parent_phases.hold(obj, type); } if (phb_rp->version == 3) { diff --git a/hw/pci-host/pnv_phb3_msi.c b/hw/pci-host/pnv_phb3_msi.c index dc8d863..a6d827f 100644 --- a/hw/pci-host/pnv_phb3_msi.c +++ b/hw/pci-host/pnv_phb3_msi.c @@ -228,13 +228,13 @@ static void phb3_msi_resend(ICSState *ics) } } -static void phb3_msi_reset_hold(Object *obj) +static void phb3_msi_reset_hold(Object *obj, ResetType type) { Phb3MsiState *msi = PHB3_MSI(obj); ICSStateClass *icsc = ICS_GET_CLASS(obj); if (icsc->parent_phases.hold) { - icsc->parent_phases.hold(obj); + icsc->parent_phases.hold(obj, type); } memset(msi->rba, 0, sizeof(msi->rba)); diff --git a/hw/pci/pci.c b/hw/pci/pci.c index e7a39cb..324c130 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -64,7 +64,7 @@ bool pci_available = true; static char *pcibus_get_dev_path(DeviceState *dev); static char *pcibus_get_fw_dev_path(DeviceState *dev); -static void pcibus_reset_hold(Object *obj); +static void pcibus_reset_hold(Object *obj, ResetType type); static bool pcie_has_upstream_port(PCIDevice *dev); static Property pci_props[] = { @@ -427,7 +427,7 @@ void pci_device_reset(PCIDevice *dev) * Called via bus_cold_reset on RST# assert, after the devices * have been reset device_cold_reset-ed already. */ -static void pcibus_reset_hold(Object *obj) +static void pcibus_reset_hold(Object *obj, ResetType type) { PCIBus *bus = PCI_BUS(obj); int i; diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c index f4c1869..3379f92 100644 --- a/hw/rtc/mc146818rtc.c +++ b/hw/rtc/mc146818rtc.c @@ -998,7 +998,7 @@ static void rtc_reset_enter(Object *obj, ResetType type) } } -static void rtc_reset_hold(Object *obj) +static void rtc_reset_hold(Object *obj, ResetType type) { MC146818RtcState *s = MC146818_RTC(obj); diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c index 34639f2..8657ff7 100644 --- a/hw/s390x/css-bridge.c +++ b/hw/s390x/css-bridge.c @@ -56,7 +56,7 @@ static void ccw_device_unplug(HotplugHandler *hotplug_dev, qdev_unrealize(dev); } -static void virtual_css_bus_reset_hold(Object *obj) +static void virtual_css_bus_reset_hold(Object *obj, ResetType type) { /* This should actually be modelled via the generic css */ css_reset(); diff --git a/hw/sensor/adm1266.c b/hw/sensor/adm1266.c index 5454b73..25b87a7 100644 --- a/hw/sensor/adm1266.c +++ b/hw/sensor/adm1266.c @@ -76,7 +76,7 @@ static const uint8_t adm1266_ic_device_id[] = {0x03, 0x41, 0x12, 0x66}; static const uint8_t adm1266_ic_device_rev[] = {0x08, 0x01, 0x08, 0x07, 0x0, 0x0, 0x07, 0x41, 0x30}; -static void adm1266_exit_reset(Object *obj) +static void adm1266_exit_reset(Object *obj, ResetType type) { ADM1266State *s = ADM1266(obj); PMBusDevice *pmdev = PMBUS_DEVICE(obj); diff --git a/hw/sensor/adm1272.c b/hw/sensor/adm1272.c index 1f7c8ab..3fc1e5d 100644 --- a/hw/sensor/adm1272.c +++ b/hw/sensor/adm1272.c @@ -185,7 +185,7 @@ static uint32_t adm1272_direct_to_watts(uint16_t value) return pmbus_direct_mode2data(c, value); } -static void adm1272_exit_reset(Object *obj) +static void adm1272_exit_reset(Object *obj, ResetType type) { ADM1272State *s = ADM1272(obj); PMBusDevice *pmdev = PMBUS_DEVICE(obj); @@ -386,7 +386,7 @@ static int adm1272_write_data(PMBusDevice *pmdev, const uint8_t *buf, break; case ADM1272_MFR_POWER_CYCLE: - adm1272_exit_reset((Object *)s); + device_cold_reset(DEVICE(s)); break; case ADM1272_HYSTERESIS_LOW: diff --git a/hw/sensor/isl_pmbus_vr.c b/hw/sensor/isl_pmbus_vr.c index e51269f..304a66e 100644 --- a/hw/sensor/isl_pmbus_vr.c +++ b/hw/sensor/isl_pmbus_vr.c @@ -63,7 +63,7 @@ static void isl_pmbus_vr_set(Object *obj, Visitor *v, const char *name, pmbus_check_limits(pmdev); } -static void isl_pmbus_vr_exit_reset(Object *obj) +static void isl_pmbus_vr_exit_reset(Object *obj, ResetType type) { PMBusDevice *pmdev = PMBUS_DEVICE(obj); @@ -102,11 +102,11 @@ static void isl_pmbus_vr_exit_reset(Object *obj) } /* The raa228000 uses different direct mode coefficients from most isl devices */ -static void raa228000_exit_reset(Object *obj) +static void raa228000_exit_reset(Object *obj, ResetType type) { PMBusDevice *pmdev = PMBUS_DEVICE(obj); - isl_pmbus_vr_exit_reset(obj); + isl_pmbus_vr_exit_reset(obj, type); pmdev->pages[0].read_iout = 0; pmdev->pages[0].read_pout = 0; @@ -119,13 +119,13 @@ static void raa228000_exit_reset(Object *obj) pmdev->pages[0].read_temperature_3 = 0; } -static void isl69259_exit_reset(Object *obj) +static void isl69259_exit_reset(Object *obj, ResetType type) { ISLState *s = ISL69260(obj); static const uint8_t ic_device_id[] = {0x04, 0x00, 0x81, 0xD2, 0x49, 0x3c}; g_assert(sizeof(ic_device_id) <= sizeof(s->ic_device_id)); - isl_pmbus_vr_exit_reset(obj); + isl_pmbus_vr_exit_reset(obj, type); s->ic_device_id_len = sizeof(ic_device_id); memcpy(s->ic_device_id, ic_device_id, sizeof(ic_device_id)); diff --git a/hw/sensor/max31785.c b/hw/sensor/max31785.c index 916ed4d..3577a7c 100644 --- a/hw/sensor/max31785.c +++ b/hw/sensor/max31785.c @@ -444,7 +444,7 @@ static int max31785_write_data(PMBusDevice *pmdev, const uint8_t *buf, return 0; } -static void max31785_exit_reset(Object *obj) +static void max31785_exit_reset(Object *obj, ResetType type) { PMBusDevice *pmdev = PMBUS_DEVICE(obj); MAX31785State *s = MAX31785(obj); diff --git a/hw/sensor/max34451.c b/hw/sensor/max34451.c index 031ae53..93b53f3 100644 --- a/hw/sensor/max34451.c +++ b/hw/sensor/max34451.c @@ -608,7 +608,7 @@ static inline void *memset_word(void *s, uint16_t c, size_t n) return s; } -static void max34451_exit_reset(Object *obj) +static void max34451_exit_reset(Object *obj, ResetType type) { PMBusDevice *pmdev = PMBUS_DEVICE(obj); MAX34451State *s = MAX34451(obj); diff --git a/hw/ssi/npcm7xx_fiu.c b/hw/ssi/npcm7xx_fiu.c index 81dd972..119c38c 100644 --- a/hw/ssi/npcm7xx_fiu.c +++ b/hw/ssi/npcm7xx_fiu.c @@ -483,7 +483,7 @@ static void npcm7xx_fiu_enter_reset(Object *obj, ResetType type) s->regs[NPCM7XX_FIU_CFG] = 0x0000000b; } -static void npcm7xx_fiu_hold_reset(Object *obj) +static void npcm7xx_fiu_hold_reset(Object *obj, ResetType type) { NPCM7xxFIUState *s = NPCM7XX_FIU(obj); int i; diff --git a/hw/timer/etraxfs_timer.c b/hw/timer/etraxfs_timer.c index da7c946..dd6d96b 100644 --- a/hw/timer/etraxfs_timer.c +++ b/hw/timer/etraxfs_timer.c @@ -357,7 +357,7 @@ static void etraxfs_timer_reset_enter(Object *obj, ResetType type) t->rw_intr_mask = 0; } -static void etraxfs_timer_reset_hold(Object *obj) +static void etraxfs_timer_reset_hold(Object *obj, ResetType type) { ETRAXTimerState *t = ETRAX_TIMER(obj); diff --git a/hw/timer/npcm7xx_timer.c b/hw/timer/npcm7xx_timer.c index 779c604..c55ba02 100644 --- a/hw/timer/npcm7xx_timer.c +++ b/hw/timer/npcm7xx_timer.c @@ -592,7 +592,7 @@ static void npcm7xx_watchdog_timer_expired(void *opaque) } } -static void npcm7xx_timer_hold_reset(Object *obj) +static void npcm7xx_timer_hold_reset(Object *obj, ResetType type) { NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(obj); int i; diff --git a/hw/usb/hcd-dwc2.c b/hw/usb/hcd-dwc2.c index 222eef8..8cac9c0 100644 --- a/hw/usb/hcd-dwc2.c +++ b/hw/usb/hcd-dwc2.c @@ -1305,7 +1305,7 @@ static void dwc2_reset_enter(Object *obj, ResetType type) } } -static void dwc2_reset_hold(Object *obj) +static void dwc2_reset_hold(Object *obj, ResetType type) { DWC2Class *c = DWC2_USB_GET_CLASS(obj); DWC2State *s = DWC2_USB(obj); @@ -1313,13 +1313,13 @@ static void dwc2_reset_hold(Object *obj) trace_usb_dwc2_reset_hold(); if (c->parent_phases.hold) { - c->parent_phases.hold(obj); + c->parent_phases.hold(obj, type); } dwc2_update_irq(s); } -static void dwc2_reset_exit(Object *obj) +static void dwc2_reset_exit(Object *obj, ResetType type) { DWC2Class *c = DWC2_USB_GET_CLASS(obj); DWC2State *s = DWC2_USB(obj); @@ -1327,7 +1327,7 @@ static void dwc2_reset_exit(Object *obj) trace_usb_dwc2_reset_exit(); if (c->parent_phases.exit) { - c->parent_phases.exit(obj); + c->parent_phases.exit(obj, type); } s->hprt0 = HPRT0_PWR; diff --git a/hw/usb/xlnx-versal-usb2-ctrl-regs.c b/hw/usb/xlnx-versal-usb2-ctrl-regs.c index 6fc4538..66c793a 100644 --- a/hw/usb/xlnx-versal-usb2-ctrl-regs.c +++ b/hw/usb/xlnx-versal-usb2-ctrl-regs.c @@ -153,7 +153,7 @@ static void usb2_ctrl_regs_reset_init(Object *obj, ResetType type) } } -static void usb2_ctrl_regs_reset_hold(Object *obj) +static void usb2_ctrl_regs_reset_hold(Object *obj, ResetType type) { VersalUsb2CtrlRegs *s = XILINX_VERSAL_USB2_CTRL_REGS(obj); diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index cb159fd..b1d02f4 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -2292,7 +2292,7 @@ static void virtio_pci_reset(DeviceState *qdev) } } -static void virtio_pci_bus_reset_hold(Object *obj) +static void virtio_pci_bus_reset_hold(Object *obj, ResetType type) { PCIDevice *dev = PCI_DEVICE(obj); DeviceState *qdev = DEVICE(obj); |